001/* 002 * Configurate 003 * Copyright (C) zml and Configurate contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package ninja.leaping.configurate; 018 019import com.google.common.collect.ImmutableSet; 020import com.google.common.primitives.Primitives; 021import ninja.leaping.configurate.loader.ConfigurationLoader; 022import ninja.leaping.configurate.objectmapping.DefaultObjectMapperFactory; 023import ninja.leaping.configurate.objectmapping.ObjectMapperFactory; 024import ninja.leaping.configurate.objectmapping.serialize.TypeSerializerCollection; 025import ninja.leaping.configurate.util.MapFactories; 026import ninja.leaping.configurate.util.MapFactory; 027import org.checkerframework.checker.nullness.qual.NonNull; 028import org.checkerframework.checker.nullness.qual.Nullable; 029 030import java.util.Objects; 031import java.util.Set; 032import java.util.function.Consumer; 033 034import static java.util.Objects.requireNonNull; 035 036/** 037 * This object is a holder for general configuration options. 038 * 039 * <p>This is meant to hold options that are used in configuring how the configuration data 040 * structures are handled, rather than the serialization configuration that is located in {@link 041 * ConfigurationLoader}s.</p> 042 * 043 * <p>This class is immutable.</p> 044 */ 045public class ConfigurationOptions { 046 private static final ConfigurationOptions DEFAULTS = new ConfigurationOptions(MapFactories.insertionOrdered(), null, 047 TypeSerializerCollection.defaults(), null, DefaultObjectMapperFactory.getInstance(), false); 048 @NonNull 049 private final MapFactory mapFactory; 050 @Nullable 051 private final String header; 052 @NonNull 053 private final TypeSerializerCollection serializers; 054 @Nullable 055 private final ImmutableSet<Class<?>> acceptedTypes; 056 @NonNull 057 private final ObjectMapperFactory objectMapperFactory; 058 private final boolean shouldCopyDefaults; 059 060 private ConfigurationOptions(@NonNull MapFactory mapFactory, @Nullable String header, @NonNull TypeSerializerCollection serializers, @Nullable Set<Class<?>> acceptedTypes, @NonNull ObjectMapperFactory objectMapperFactory, boolean shouldCopyDefaults) { 061 this.mapFactory = mapFactory; 062 this.header = header; 063 this.serializers = serializers; 064 this.acceptedTypes = acceptedTypes == null ? null : ImmutableSet.copyOf(acceptedTypes); 065 this.objectMapperFactory = objectMapperFactory; 066 this.shouldCopyDefaults = shouldCopyDefaults; 067 } 068 069 /** 070 * Get the default set of options. This may be overridden by your chosen configuration loader, so when building 071 * configurations it is recommended to access {@code AbstractConfigurationLoader.Builder#getDefaultOptions()} 072 * instead. 073 * 074 * @return the default options 075 */ 076 @NonNull 077 public static ConfigurationOptions defaults() { 078 return DEFAULTS; 079 } 080 081 /** 082 * Gets the {@link MapFactory} specified in these options. 083 * 084 * @return The map factory 085 */ 086 @NonNull 087 public MapFactory getMapFactory() { 088 return mapFactory; 089 } 090 091 /** 092 * Creates a new {@link ConfigurationOptions} instance, with the specified {@link MapFactory} set, and all other 093 * settings copied from this instance. 094 * 095 * @param mapFactory The new factory to use to create a map 096 * @return The new options object 097 * @deprecated USe {@link #withMapFactory(MapFactory)} instead 098 */ 099 @NonNull 100 @Deprecated 101 public ConfigurationOptions setMapFactory(@NonNull MapFactory mapFactory) { 102 return withMapFactory(mapFactory); 103 } 104 105 /** 106 * Creates a new {@link ConfigurationOptions} instance, with the specified {@link MapFactory} set, and all other 107 * settings copied from this instance. 108 * 109 * @param mapFactory The new factory to use to create a map 110 * @return The new options object 111 */ 112 @NonNull 113 public ConfigurationOptions withMapFactory(@NonNull MapFactory mapFactory) { 114 requireNonNull(mapFactory, "mapFactory"); 115 if (this.mapFactory == mapFactory) { 116 return this; 117 } 118 return new ConfigurationOptions(mapFactory, header, serializers, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 119 } 120 121 /** 122 * Gets the header specified in these options. 123 * 124 * @return The current header. Lines are split by \n, 125 */ 126 @Nullable 127 public String getHeader() { 128 return this.header; 129 } 130 131 /** 132 * Creates a new {@link ConfigurationOptions} instance, with the specified header set, and all other settings copied 133 * from this instance. 134 * 135 * @param header The new header to use 136 * @return The new options object 137 */ 138 @NonNull 139 public ConfigurationOptions setHeader(@Nullable String header) { 140 return withHeader(header); 141 } 142 143 /** 144 * Creates a new {@link ConfigurationOptions} instance, with the specified header set, and all other settings copied 145 * from this instance. 146 * 147 * @param header The new header to use 148 * @return The new options object 149 */ 150 @NonNull 151 public ConfigurationOptions withHeader(@Nullable String header) { 152 if (Objects.equals(this.header, header)) { 153 return this; 154 } 155 return new ConfigurationOptions(mapFactory, header, serializers, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 156 } 157 158 /** 159 * Gets the {@link TypeSerializerCollection} specified in these options. 160 * 161 * @return The type serializers 162 */ 163 @NonNull 164 public TypeSerializerCollection getSerializers() { 165 return this.serializers; 166 } 167 168 /** 169 * Creates a new {@link ConfigurationOptions} instance, with the specified {@link TypeSerializerCollection} set, and 170 * all other settings copied from this instance. 171 * 172 * @param serializers The serializers to use 173 * @return The new options object 174 * @deprecated Use {@link #withSerializers(TypeSerializerCollection)} instead 175 */ 176 @NonNull 177 @Deprecated 178 public ConfigurationOptions setSerializers(@NonNull TypeSerializerCollection serializers) { 179 return withSerializers(serializers); 180 } 181 182 /** 183 * Creates a new {@link ConfigurationOptions} instance, with the specified {@link TypeSerializerCollection} set, and 184 * all other settings copied from this instance. 185 * 186 * @param serializers The serializers to use 187 * @return The new options object 188 */ 189 @NonNull 190 public ConfigurationOptions withSerializers(@NonNull TypeSerializerCollection serializers) { 191 requireNonNull(serializers, "serializers"); 192 if (this.serializers == serializers) { 193 return this; 194 } 195 return new ConfigurationOptions(mapFactory, header, serializers, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 196 } 197 198 /** 199 * Creates a new {@link ConfigurationOptions} instance, with a new {@link TypeSerializerCollection} created as a 200 * child of this options' current collection. The provided function will be called with the builder for this new 201 * collection to allow registering more type serializers. 202 * 203 * @param serializerBuilder accepts a builder for the collection that will be used in the returned options object. 204 * @return The new options object 205 */ 206 public @NonNull ConfigurationOptions withSerializers(@NonNull Consumer<TypeSerializerCollection> serializerBuilder) { 207 requireNonNull(serializerBuilder, "serializerBuilder"); 208 final TypeSerializerCollection builder = this.serializers.newChild(); 209 serializerBuilder.accept(builder); 210 return new ConfigurationOptions(mapFactory, header, builder, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 211 } 212 213 /** 214 * Gets the {@link ObjectMapperFactory} specified in these options. 215 * 216 * @return The factory used to construct ObjectMapper instances 217 */ 218 @NonNull 219 public ObjectMapperFactory getObjectMapperFactory() { 220 return this.objectMapperFactory; 221 } 222 223 /** 224 * Creates a new {@link ConfigurationOptions} instance, with the specified {@link ObjectMapperFactory} set, and all 225 * other settings copied from this instance. 226 * 227 * @param objectMapperFactory The factory to use to produce object mapper instances. Must not be null 228 * @return updated options object 229 * @deprecated Use {@link #withObjectMapperFactory(ObjectMapperFactory)} instead 230 */ 231 @NonNull 232 @Deprecated 233 public ConfigurationOptions setObjectMapperFactory(@NonNull ObjectMapperFactory objectMapperFactory) { 234 return withObjectMapperFactory(objectMapperFactory); 235 } 236 237 /** 238 * Creates a new {@link ConfigurationOptions} instance, with the specified {@link ObjectMapperFactory} set, and all 239 * other settings copied from this instance. 240 * 241 * @param objectMapperFactory The factory to use to produce object mapper instances. Must not be null 242 * @return updated options object 243 */ 244 @NonNull 245 public ConfigurationOptions withObjectMapperFactory(@NonNull ObjectMapperFactory objectMapperFactory) { 246 requireNonNull(objectMapperFactory, "factory"); 247 if (this.objectMapperFactory == objectMapperFactory) { 248 return this; 249 } 250 return new ConfigurationOptions(mapFactory, header, serializers, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 251 } 252 253 /** 254 * Gets whether objects of the provided type are accepted as values for nodes with this as their options object. 255 * 256 * @param type The type to check 257 * @return Whether the type is accepted 258 */ 259 public boolean acceptsType(@NonNull Class<?> type) { 260 requireNonNull(type, "type"); 261 262 if (this.acceptedTypes == null) { 263 return true; 264 } 265 if (this.acceptedTypes.contains(type)) { 266 return true; 267 } 268 269 if (type.isPrimitive() && this.acceptedTypes.contains(Primitives.wrap(type))) { 270 return true; 271 } 272 273 if (Primitives.isWrapperType(type) && this.acceptedTypes.contains(Primitives.unwrap(type))) { 274 return true; 275 } 276 277 for (Class<?> clazz : this.acceptedTypes) { 278 if (clazz.isAssignableFrom(type)) { 279 return true; 280 } 281 } 282 283 return false; 284 } 285 286 /** 287 * Creates a new {@link ConfigurationOptions} instance, with the specified accepted types set, and all other 288 * settings copied from this instance. 289 * 290 * <p>'Accepted types' are types which are accepted as native values for the configuration.</p> 291 * 292 * <p>Null indicates that all types are accepted.</p> 293 * 294 * @param acceptedTypes The types that will be accepted to a call to {@link ConfigurationNode#setValue(Object)} 295 * @return updated options object 296 * @deprecated Use {@link #withNativeTypes(Set)} instead 297 */ 298 @NonNull 299 @Deprecated 300 public ConfigurationOptions setAcceptedTypes(@Nullable Set<Class<?>> acceptedTypes) { 301 return withNativeTypes(acceptedTypes); 302 } 303 304 /** 305 * Creates a new {@link ConfigurationOptions} instance, with the specified native types set, and all other settings 306 * copied from this instance. 307 * <p> 308 * Native types are format-dependent, and must be provided by a configuration loader's {@link 309 * ConfigurationLoader#getDefaultOptions() default options}. 310 * 311 * <p>Null indicates that all types are accepted. Setting this may result in unexpected changes to values</p> 312 * 313 * @param acceptedTypes The types that will be accepted to a call to {@link ConfigurationNode#setValue(Object)} 314 * @return updated options object 315 */ 316 @NonNull 317 public ConfigurationOptions withNativeTypes(@Nullable Set<Class<?>> acceptedTypes) { 318 if (Objects.equals(this.acceptedTypes, acceptedTypes)) { 319 return this; 320 } 321 322 return new ConfigurationOptions(mapFactory, header, serializers, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 323 } 324 325 /** 326 * Gets whether or not default parameters provided to {@link ConfigurationNode} getter methods should be set to the 327 * node when used. 328 * 329 * @return Whether defaults should be copied into value 330 */ 331 public boolean shouldCopyDefaults() { 332 return shouldCopyDefaults; 333 } 334 335 /** 336 * Creates a new {@link ConfigurationOptions} instance, with the specified 'copy defaults' setting set, and all 337 * other settings copied from this instance. 338 * 339 * @param shouldCopyDefaults whether to copy defaults 340 * @return updated options object 341 * @see #shouldCopyDefaults() for information on what this method does 342 * @deprecated Use {@link #withShouldCopyDefaults(boolean)} 343 */ 344 @NonNull 345 @Deprecated 346 public ConfigurationOptions setShouldCopyDefaults(boolean shouldCopyDefaults) { 347 return withShouldCopyDefaults(shouldCopyDefaults); 348 } 349 350 /** 351 * Creates a new {@link ConfigurationOptions} instance, with the specified 'copy defaults' setting set, and all 352 * other settings copied from this instance. 353 * 354 * @param shouldCopyDefaults wether to copy defaults 355 * @return updated options object 356 * @see #shouldCopyDefaults() for information on what this method does 357 */ 358 @NonNull 359 public ConfigurationOptions withShouldCopyDefaults(boolean shouldCopyDefaults) { 360 if (this.shouldCopyDefaults == shouldCopyDefaults) { 361 return this; 362 } 363 return new ConfigurationOptions(mapFactory, header, serializers, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 364 } 365 366 @Override 367 public boolean equals(Object o) { 368 if (this == o) return true; 369 if (!(o instanceof ConfigurationOptions)) return false; 370 ConfigurationOptions that = (ConfigurationOptions) o; 371 return Objects.equals(shouldCopyDefaults, that.shouldCopyDefaults) && 372 Objects.equals(mapFactory, that.mapFactory) && 373 Objects.equals(header, that.header) && 374 Objects.equals(serializers, that.serializers) && 375 Objects.equals(acceptedTypes, that.acceptedTypes) && 376 Objects.equals(objectMapperFactory, that.objectMapperFactory); 377 } 378 379 @Override 380 public int hashCode() { 381 return Objects.hash(mapFactory, header, serializers, acceptedTypes, objectMapperFactory, shouldCopyDefaults); 382 } 383 384 @Override 385 public String toString() { 386 return "ConfigurationOptions{" + 387 "mapFactory=" + mapFactory + 388 ", header='" + header + '\'' + 389 ", serializers=" + serializers + 390 ", acceptedTypes=" + acceptedTypes + 391 ", objectMapperFactory=" + objectMapperFactory + 392 ", shouldCopyDefaults=" + shouldCopyDefaults + 393 '}'; 394 } 395}