Skip to content

Commit

Permalink
Merge pull request #169 from SpongePowered/feature/implicit-initializ…
Browse files Browse the repository at this point in the history
…ation

Support implicit node initialization
  • Loading branch information
zml2008 authored Oct 3, 2020
2 parents ab33a8a + 962e636 commit 74a255f
Show file tree
Hide file tree
Showing 20 changed files with 414 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ protected AbstractConfigurationNode(final @Nullable A parent, final A copyOf) {
*/
static <V> V storeDefault(final ConfigurationNode node, final V defValue) {
requireNonNull(defValue, "defValue");
if (node.getOptions().shouldCopyDefaults()) {
if (node.getOptions().getShouldCopyDefaults()) {
node.setValue(defValue);
}
return defValue;
}

static <V> V storeDefault(final ConfigurationNode node, final Type type, final V defValue) throws ObjectMappingException {
requireNonNull(defValue, "defValue");
if (node.getOptions().shouldCopyDefaults()) {
if (node.getOptions().getShouldCopyDefaults()) {
node.setValue(type, defValue);
}
return defValue;
Expand All @@ -143,11 +143,17 @@ static <V> V storeDefault(final ConfigurationNode node, final Type type, final V
throw new IllegalArgumentException("Raw types are not supported");
}

if (isVirtual()) {
final @Nullable TypeSerializer<?> serial = getOptions().getSerializers().get(type);
if (this.value instanceof NullConfigValue) {
if (serial != null && getOptions().isImplicitInitialization()) {
final @Nullable Object emptyValue = serial.emptyValue(type, this.options);
if (emptyValue != null) {
return storeDefault(this, type, emptyValue);
}
}
return null;
}

final @Nullable TypeSerializer<?> serial = getOptions().getSerializers().get(type);
if (serial == null) {
final @Nullable Object value = getValue();
final Class<?> erasure = erase(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ default String getString(final String def) {
if (value != null) {
return value;
}
if (getOptions().shouldCopyDefaults()) {
if (getOptions().getShouldCopyDefaults()) {
setValue(def);
}
return def;
Expand Down Expand Up @@ -662,7 +662,7 @@ default float getFloat(float def) {
if (val != null) {
return val;
}
if (getOptions().shouldCopyDefaults() && def != NUMBER_DEF) {
if (getOptions().getShouldCopyDefaults() && def != NUMBER_DEF) {
setValue(def);
}
return def;
Expand Down Expand Up @@ -690,7 +690,7 @@ default double getDouble(double def) {
if (val != null) {
return val;
}
if (getOptions().shouldCopyDefaults() && def != NUMBER_DEF) {
if (getOptions().getShouldCopyDefaults() && def != NUMBER_DEF) {
setValue(def);
}
return def;
Expand Down Expand Up @@ -718,7 +718,7 @@ default int getInt(int def) {
if (val != null) {
return val;
}
if (getOptions().shouldCopyDefaults() && def != NUMBER_DEF) {
if (getOptions().getShouldCopyDefaults() && def != NUMBER_DEF) {
setValue(def);
}
return def;
Expand Down Expand Up @@ -746,7 +746,7 @@ default long getLong(long def) {
if (val != null) {
return val;
}
if (getOptions().shouldCopyDefaults() && def != NUMBER_DEF) {
if (getOptions().getShouldCopyDefaults() && def != NUMBER_DEF) {
setValue(def);
}
return def;
Expand Down Expand Up @@ -774,7 +774,7 @@ default boolean getBoolean(boolean def) {
if (val != null) {
return val;
}
if (getOptions().shouldCopyDefaults()) {
if (getOptions().getShouldCopyDefaults()) {
setValue(def);
}
return def;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import static java.util.Objects.requireNonNull;

import com.google.auto.value.AutoValue;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.loader.ConfigurationLoader;
import org.spongepowered.configurate.serialize.TypeSerializerCollection;
Expand All @@ -40,24 +41,19 @@
*
* <p>This class is immutable.</p>
*/
public final class ConfigurationOptions {

private static final ConfigurationOptions DEFAULTS = new ConfigurationOptions(MapFactories.insertionOrdered(), null,
TypeSerializerCollection.defaults(), null, false);

private final MapFactory mapFactory;
private final @Nullable String header;
private final TypeSerializerCollection serializers;
private final @Nullable Set<Class<?>> acceptedTypes;
private final boolean shouldCopyDefaults;

private ConfigurationOptions(final MapFactory mapFactory, final @Nullable String header, final TypeSerializerCollection serializers,
final @Nullable Set<Class<?>> acceptedTypes, final boolean shouldCopyDefaults) {
this.mapFactory = mapFactory;
this.header = header;
this.serializers = serializers;
this.acceptedTypes = acceptedTypes == null ? null : UnmodifiableCollections.copyOf(acceptedTypes);
this.shouldCopyDefaults = shouldCopyDefaults;
@AutoValue
public abstract class ConfigurationOptions {

static class Lazy {

// avoid initialization cycles

static final ConfigurationOptions DEFAULTS = new AutoValue_ConfigurationOptions(MapFactories.insertionOrdered(), null,
TypeSerializerCollection.defaults(), null, false, false);

}

ConfigurationOptions() {
}

/**
Expand All @@ -69,17 +65,15 @@ private ConfigurationOptions(final MapFactory mapFactory, final @Nullable String
* @return the default options
*/
public static ConfigurationOptions defaults() {
return DEFAULTS;
return Lazy.DEFAULTS;
}

/**
* Gets the {@link MapFactory} specified in these options.
*
* @return The map factory
*/
public MapFactory getMapFactory() {
return this.mapFactory;
}
public abstract MapFactory getMapFactory();

/**
* Creates a new {@link ConfigurationOptions} instance, with the specified
Expand All @@ -90,20 +84,19 @@ public MapFactory getMapFactory() {
*/
public ConfigurationOptions withMapFactory(final MapFactory mapFactory) {
requireNonNull(mapFactory, "mapFactory");
if (this.mapFactory == mapFactory) {
if (this.getMapFactory() == mapFactory) {
return this;
}
return new ConfigurationOptions(mapFactory, this.header, this.serializers, this.acceptedTypes, this.shouldCopyDefaults);
return new AutoValue_ConfigurationOptions(mapFactory, getHeader(), getSerializers(), getNativeTypes(),
getShouldCopyDefaults(), isImplicitInitialization());
}

/**
* Gets the header specified in these options.
*
* @return The current header. Lines are split by \n,
*/
public @Nullable String getHeader() {
return this.header;
}
public abstract @Nullable String getHeader();

/**
* Creates a new {@link ConfigurationOptions} instance, with the specified
Expand All @@ -113,20 +106,19 @@ public ConfigurationOptions withMapFactory(final MapFactory mapFactory) {
* @return The new options object
*/
public ConfigurationOptions withHeader(final @Nullable String header) {
if (Objects.equals(this.header, header)) {
if (Objects.equals(this.getHeader(), header)) {
return this;
}
return new ConfigurationOptions(this.mapFactory, header, this.serializers, this.acceptedTypes, this.shouldCopyDefaults);
return new AutoValue_ConfigurationOptions(getMapFactory(), header, getSerializers(), getNativeTypes(),
getShouldCopyDefaults(), isImplicitInitialization());
}

/**
* Gets the {@link TypeSerializerCollection} specified in these options.
*
* @return The type serializers
*/
public TypeSerializerCollection getSerializers() {
return this.serializers;
}
public abstract TypeSerializerCollection getSerializers();

/**
* Creates a new {@link ConfigurationOptions} instance, with the specified {@link TypeSerializerCollection}
Expand All @@ -137,10 +129,11 @@ public TypeSerializerCollection getSerializers() {
*/
public ConfigurationOptions withSerializers(final TypeSerializerCollection serializers) {
requireNonNull(serializers, "serializers");
if (this.serializers.equals(serializers)) {
if (this.getSerializers().equals(serializers)) {
return this;
}
return new ConfigurationOptions(this.mapFactory, this.header, serializers, this.acceptedTypes, this.shouldCopyDefaults);
return new AutoValue_ConfigurationOptions(getMapFactory(), getHeader(), serializers, getNativeTypes(),
getShouldCopyDefaults(), isImplicitInitialization());
}

/**
Expand All @@ -153,40 +146,46 @@ public ConfigurationOptions withSerializers(final TypeSerializerCollection seria
* be used in the returned options object.
* @return The new options object
*/
public ConfigurationOptions withSerializers(final Consumer<TypeSerializerCollection.Builder> serializerBuilder) {
public final ConfigurationOptions withSerializers(final Consumer<TypeSerializerCollection.Builder> serializerBuilder) {
requireNonNull(serializerBuilder, "serializerBuilder");
final TypeSerializerCollection.Builder builder = this.serializers.childBuilder();
final TypeSerializerCollection.Builder builder = this.getSerializers().childBuilder();
serializerBuilder.accept(builder);
return new ConfigurationOptions(this.mapFactory, this.header, builder.build(), this.acceptedTypes, this.shouldCopyDefaults);
return withSerializers(builder.build());
}

@SuppressWarnings("AutoValueImmutableFields") // we don't use guava
abstract @Nullable Set<Class<?>> getNativeTypes();

/**
* Gets whether objects of the provided type are natively accepted as values
* for nodes with this as their options object.
*
* @param type The type to check
* @return Whether the type is accepted
*/
public boolean acceptsType(final Class<?> type) {
public final boolean acceptsType(final Class<?> type) {
requireNonNull(type, "type");

if (this.acceptedTypes == null) {
final @Nullable Set<Class<?>> nativeTypes = getNativeTypes();

if (nativeTypes == null) {
return true;
}
if (this.acceptedTypes.contains(type)) {

if (nativeTypes.contains(type)) {
return true;
}

if (type.isPrimitive() && this.acceptedTypes.contains(Typing.box(type))) {
if (type.isPrimitive() && nativeTypes.contains(Typing.box(type))) {
return true;
}

final Type unboxed = Typing.unbox(type);
if (unboxed != type && this.acceptedTypes.contains(unboxed)) {
if (unboxed != type && nativeTypes.contains(unboxed)) {
return true;
}

for (Class<?> clazz : this.acceptedTypes) {
for (Class<?> clazz : nativeTypes) {
if (clazz.isAssignableFrom(type)) {
return true;
}
Expand All @@ -204,14 +203,15 @@ public boolean acceptsType(final Class<?> type) {
*
* <p>Null indicates that all types are accepted.</p>
*
* @param acceptedTypes The types that will be accepted to a call to {@link ConfigurationNode#setValue(Object)}
* @param nativeTypes The types that will be accepted to a call to {@link ConfigurationNode#setValue(Object)}
* @return updated options object
*/
public ConfigurationOptions withNativeTypes(final @Nullable Set<Class<?>> acceptedTypes) {
if (Objects.equals(this.acceptedTypes, acceptedTypes)) {
public ConfigurationOptions withNativeTypes(final @Nullable Set<Class<?>> nativeTypes) {
if (Objects.equals(this.getNativeTypes(), nativeTypes)) {
return this;
}
return new ConfigurationOptions(this.mapFactory, this.header, this.serializers, acceptedTypes, this.shouldCopyDefaults);
return new AutoValue_ConfigurationOptions(getMapFactory(), getHeader(), getSerializers(),
nativeTypes == null ? null : UnmodifiableCollections.copyOf(nativeTypes), getShouldCopyDefaults(), isImplicitInitialization());
}

/**
Expand All @@ -220,57 +220,54 @@ public ConfigurationOptions withNativeTypes(final @Nullable Set<Class<?>> accept
*
* @return Whether defaults should be copied into value
*/
public boolean shouldCopyDefaults() {
return this.shouldCopyDefaults;
}
public abstract boolean getShouldCopyDefaults();

/**
* Creates a new {@link ConfigurationOptions} instance, with the specified 'copy defaults' setting
* set, and all other settings copied from this instance.
* Creates a new {@link ConfigurationOptions} instance, with the specified
* 'copy defaults' setting set, and all other settings copied from
* this instance.
*
* @see #shouldCopyDefaults() for information on what this method does
* @see #getShouldCopyDefaults() for information on what this method does
* @param shouldCopyDefaults whether to copy defaults
* @return updated options object
*/
public ConfigurationOptions withShouldCopyDefaults(final boolean shouldCopyDefaults) {
if (this.shouldCopyDefaults == shouldCopyDefaults) {
if (this.getShouldCopyDefaults() == shouldCopyDefaults) {
return this;
}
return new ConfigurationOptions(this.mapFactory, this.header, this.serializers, this.acceptedTypes, shouldCopyDefaults);

return new AutoValue_ConfigurationOptions(getMapFactory(), getHeader(), getSerializers(), getNativeTypes(),
shouldCopyDefaults, isImplicitInitialization());
}

@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
/**
* Get whether values should be implicitly initialized.
*
* <p>When this is true, any value get operations will return an empty value
* rather than null. This extends through to fields loaded into
* object-mapped classes.</p>
*
* <p>This option is disabled by default</p>
*
* @return if implicit initialization is enabled.
*/
public abstract boolean isImplicitInitialization();

if (!(other instanceof ConfigurationOptions)) {
return false;
/**
* Create a new {@link ConfigurationOptions} instance with the specified
* implicit initialization setting.
*
* @param implicitInitialization whether to initialize implicitly
* @return a new options object
* @see #isImplicitInitialization() for more details
*/
public ConfigurationOptions withImplicitInitialization(final boolean implicitInitialization) {
if (this.isImplicitInitialization() == implicitInitialization) {
return this;
}

final ConfigurationOptions that = (ConfigurationOptions) other;
return Objects.equals(this.shouldCopyDefaults, that.shouldCopyDefaults)
&& Objects.equals(this.mapFactory, that.mapFactory)
&& Objects.equals(this.header, that.header)
&& Objects.equals(this.serializers, that.serializers)
&& Objects.equals(this.acceptedTypes, that.acceptedTypes);
}

@Override
public int hashCode() {
return Objects.hash(this.mapFactory, this.header, this.serializers, this.acceptedTypes, this.shouldCopyDefaults);
}

@Override
public String toString() {
return "ConfigurationOptions{"
+ "mapFactory=" + this.mapFactory
+ ", header='" + this.header + '\''
+ ", serializers=" + this.serializers
+ ", acceptedTypes=" + this.acceptedTypes
+ ", shouldCopyDefaults=" + this.shouldCopyDefaults
+ '}';
return new AutoValue_ConfigurationOptions(getMapFactory(), getHeader(), getSerializers(), getNativeTypes(),
getShouldCopyDefaults(), implicitInitialization);
}

}
Loading

0 comments on commit 74a255f

Please sign in to comment.