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 org.spongepowered.configurate; 018 019import static java.util.Objects.requireNonNull; 020 021import com.google.auto.value.AutoValue; 022import org.checkerframework.checker.nullness.qual.Nullable; 023import org.spongepowered.configurate.loader.ConfigurationLoader; 024import org.spongepowered.configurate.serialize.TypeSerializerCollection; 025import org.spongepowered.configurate.util.MapFactories; 026import org.spongepowered.configurate.util.MapFactory; 027import org.spongepowered.configurate.util.Types; 028import org.spongepowered.configurate.util.UnmodifiableCollections; 029 030import java.lang.reflect.Type; 031import java.util.Objects; 032import java.util.Set; 033import java.util.function.Consumer; 034 035/** 036 * This object is a holder for general configuration options. 037 * 038 * <p>This is meant to hold options that are used in configuring how the 039 * configuration data structures are handled, rather than the serialization 040 * configuration which is located in {@link ConfigurationLoader}s.</p> 041 * 042 * <p>This class is immutable.</p> 043 * 044 * @since 4.0.0 045 */ 046@AutoValue 047public abstract class ConfigurationOptions { 048 049 static class Lazy { 050 051 // avoid initialization cycles 052 053 static final ConfigurationOptions DEFAULTS = new AutoValue_ConfigurationOptions(MapFactories.insertionOrdered(), null, 054 TypeSerializerCollection.defaults(), null, true, true); 055 056 } 057 058 ConfigurationOptions() { 059 } 060 061 /** 062 * Get the default set of options. This may be overridden by your chosen 063 * configuration loader, so when building configurations it is recommended 064 * to access {@code AbstractConfigurationLoader.Builder#getDefaultOptions()} 065 * instead. 066 * 067 * @return the default options 068 * @since 4.0.0 069 */ 070 public static ConfigurationOptions defaults() { 071 return Lazy.DEFAULTS; 072 } 073 074 /** 075 * Gets the {@link MapFactory} specified in these options. 076 * 077 * @return the map factory 078 * @since 4.0.0 079 */ 080 public abstract MapFactory mapFactory(); 081 082 /** 083 * Creates a new {@link ConfigurationOptions} instance, with the specified 084 * {@link MapFactory} set, and all other settings copied from this instance. 085 * 086 * @param mapFactory the new factory to use to create a map 087 * @return the new options object 088 * @since 4.0.0 089 */ 090 public ConfigurationOptions mapFactory(final MapFactory mapFactory) { 091 requireNonNull(mapFactory, "mapFactory"); 092 if (this.mapFactory() == mapFactory) { 093 return this; 094 } 095 return new AutoValue_ConfigurationOptions(mapFactory, header(), serializers(), nativeTypes(), 096 shouldCopyDefaults(), implicitInitialization()); 097 } 098 099 /** 100 * Gets the header specified in these options. 101 * 102 * @return the current header. Lines are split by \n, with no 103 * trailing newline 104 * @since 4.0.0 105 */ 106 public abstract @Nullable String header(); 107 108 /** 109 * Creates a new {@link ConfigurationOptions} instance, with the specified 110 * header set, and all other settings copied from this instance. 111 * 112 * @param header the new header to use 113 * @return the new options object 114 * @since 4.0.0 115 */ 116 public ConfigurationOptions header(final @Nullable String header) { 117 if (Objects.equals(this.header(), header)) { 118 return this; 119 } 120 return new AutoValue_ConfigurationOptions(mapFactory(), header, serializers(), nativeTypes(), 121 shouldCopyDefaults(), implicitInitialization()); 122 } 123 124 /** 125 * Gets the {@link TypeSerializerCollection} specified in these options. 126 * 127 * @return the type serializers 128 * @since 4.0.0 129 */ 130 public abstract TypeSerializerCollection serializers(); 131 132 /** 133 * Creates a new {@link ConfigurationOptions} instance, with the specified {@link TypeSerializerCollection} 134 * set, and all other settings copied from this instance. 135 * 136 * @param serializers the serializers to use 137 * @return the new options object 138 * @since 4.0.0 139 */ 140 public ConfigurationOptions serializers(final TypeSerializerCollection serializers) { 141 requireNonNull(serializers, "serializers"); 142 if (this.serializers().equals(serializers)) { 143 return this; 144 } 145 return new AutoValue_ConfigurationOptions(mapFactory(), header(), serializers, nativeTypes(), 146 shouldCopyDefaults(), implicitInitialization()); 147 } 148 149 /** 150 * Creates a new {@link ConfigurationOptions} instance, with a new 151 * {@link TypeSerializerCollection} created as a child of this options' 152 * current collection. The provided function will be called with the builder 153 * for this new collection to allow registering more type serializers. 154 * 155 * @param serializerBuilder accepts a builder for the collection that will 156 * be used in the returned options object. 157 * @return the new options object 158 * @since 4.0.0 159 */ 160 public final ConfigurationOptions serializers(final Consumer<TypeSerializerCollection.Builder> serializerBuilder) { 161 requireNonNull(serializerBuilder, "serializerBuilder"); 162 final TypeSerializerCollection.Builder builder = this.serializers().childBuilder(); 163 serializerBuilder.accept(builder); 164 return serializers(builder.build()); 165 } 166 167 @SuppressWarnings("AutoValueImmutableFields") // we don't use guava 168 abstract @Nullable Set<Class<?>> nativeTypes(); 169 170 /** 171 * Creates a new {@link ConfigurationOptions} instance, with the specified native types 172 * set, and all other settings copied from this instance. 173 * 174 * <p>Native types are format-dependent, and must be provided by a 175 * configuration loader's {@link ConfigurationLoader#defaultOptions() default options}</p> 176 * 177 * <p>Null indicates that all types are accepted.</p> 178 * 179 * @param nativeTypes the types that will be accepted to a 180 * call to {@link ConfigurationNode#set(Object)} 181 * @return updated options object 182 * @since 4.0.0 183 */ 184 public ConfigurationOptions nativeTypes(final @Nullable Set<Class<?>> nativeTypes) { 185 if (Objects.equals(this.nativeTypes(), nativeTypes)) { 186 return this; 187 } 188 return new AutoValue_ConfigurationOptions(mapFactory(), header(), serializers(), 189 nativeTypes == null ? null : UnmodifiableCollections.copyOf(nativeTypes), shouldCopyDefaults(), implicitInitialization()); 190 } 191 192 /** 193 * Gets whether objects of the provided type are natively accepted as values 194 * for nodes with this as their options object. 195 * 196 * @param type the type to check 197 * @return whether the type is accepted 198 * @since 4.0.0 199 */ 200 public final boolean acceptsType(final Class<?> type) { 201 requireNonNull(type, "type"); 202 203 final @Nullable Set<Class<?>> nativeTypes = nativeTypes(); 204 205 if (nativeTypes == null) { 206 return true; 207 } 208 209 if (nativeTypes.contains(type)) { 210 return true; 211 } 212 213 if (type.isPrimitive() && nativeTypes.contains(Types.box(type))) { 214 return true; 215 } 216 217 final Type unboxed = Types.unbox(type); 218 if (unboxed != type && nativeTypes.contains(unboxed)) { 219 return true; 220 } 221 222 for (Class<?> clazz : nativeTypes) { 223 if (clazz.isAssignableFrom(type)) { 224 return true; 225 } 226 } 227 228 return false; 229 } 230 231 /** 232 * Gets whether or not default parameters provided to {@link ConfigurationNode} getter methods 233 * should be set to the node when used. 234 * 235 * @return whether defaults should be copied into value 236 * @since 4.0.0 237 */ 238 public abstract boolean shouldCopyDefaults(); 239 240 /** 241 * Creates a new {@link ConfigurationOptions} instance, with the specified 242 * 'copy defaults' setting set, and all other settings copied from 243 * this instance. 244 * 245 * @param shouldCopyDefaults whether to copy defaults 246 * @return updated options object 247 * @see #shouldCopyDefaults() for information on what this method does 248 * @since 4.0.0 249 */ 250 public ConfigurationOptions shouldCopyDefaults(final boolean shouldCopyDefaults) { 251 if (this.shouldCopyDefaults() == shouldCopyDefaults) { 252 return this; 253 } 254 255 return new AutoValue_ConfigurationOptions(mapFactory(), header(), serializers(), nativeTypes(), 256 shouldCopyDefaults, implicitInitialization()); 257 } 258 259 /** 260 * Get whether values should be implicitly initialized. 261 * 262 * <p>When this is true, any value get operations will return an empty value 263 * rather than null. This extends through to fields loaded into 264 * object-mapped classes.</p> 265 * 266 * <p>This option is disabled by default</p> 267 * 268 * @return if implicit initialization is enabled. 269 * @since 4.0.0 270 */ 271 public abstract boolean implicitInitialization(); 272 273 /** 274 * Create a new {@link ConfigurationOptions} instance with the specified 275 * implicit initialization setting. 276 * 277 * @param implicitInitialization whether to initialize implicitly 278 * @return a new options object 279 * @see #implicitInitialization() for more details 280 * @since 4.0.0 281 */ 282 public ConfigurationOptions implicitInitialization(final boolean implicitInitialization) { 283 if (this.implicitInitialization() == implicitInitialization) { 284 return this; 285 } 286 287 return new AutoValue_ConfigurationOptions(mapFactory(), header(), serializers(), nativeTypes(), 288 shouldCopyDefaults(), implicitInitialization); 289 } 290 291}