type, final Object... path) throws SerializationException {
return this.referenceTo(type, NodePath.of(path));
}
+
+ /**
+ * Create a reference to the node at the provided path. The value will be
+ * deserialized according to the provided {@link Type}.
+ *
+ * The returned reference will update with reloads of and changes to the
+ * value of the provided configuration. Any serialization errors encountered
+ * will be submitted to the {@link #errors()} stream.
+ *
+ * @param type the value's type
+ * @param path the path from the root node to the node containing the value
+ * @return a deserializing reference to the node at the given path
+ * @throws SerializationException if a type serializer could not be found
+ * for the provided type
+ * @since TODO: version
+ */
+ default ValueReference, N> referenceTo(final Type type, final NodePath path) throws SerializationException {
+ return this.referenceTo(type, path, null);
+ }
/**
* Create a reference to the node at the provided path. The value will be
@@ -351,6 +375,23 @@ default ValueReference referenceTo(final Class type, final NodePath
return this.referenceTo(type, path, null);
}
+ /**
+ * Create a reference to the node at the provided path. The value will be
+ * deserialized according to the provided {@link Type}.
+ *
+ * The returned reference will update with reloads of and changes to the
+ * value of the provided configuration. Any serialization errors encountered
+ * will be submitted to the {@link #errors()} stream.
+ *
+ * @param type the value's type
+ * @param path the path from the root node to the node containing the value
+ * @return a deserializing reference to the node at the given path
+ * @throws SerializationException if a type serializer could not be found
+ * for the provided type
+ * @since TODO: version
+ */
+ ValueReference, N> referenceTo(Type type, NodePath path, @Nullable Object defaultValue) throws SerializationException;
+
/**
* Create a reference to the node at the provided path. The value will be
* deserialized according to the provided {@link TypeToken}.
diff --git a/core/src/main/java/org/spongepowered/configurate/reference/ManualConfigurationReference.java b/core/src/main/java/org/spongepowered/configurate/reference/ManualConfigurationReference.java
index 8cbb86c93..5ddcf43e3 100644
--- a/core/src/main/java/org/spongepowered/configurate/reference/ManualConfigurationReference.java
+++ b/core/src/main/java/org/spongepowered/configurate/reference/ManualConfigurationReference.java
@@ -30,6 +30,7 @@
import org.spongepowered.configurate.reactive.Publisher;
import org.spongepowered.configurate.serialize.SerializationException;
+import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Function;
@@ -125,8 +126,13 @@ public final N get(final Iterable> path) {
}
@Override
- public final ValueReference referenceTo(final TypeToken type,
- final NodePath path, final @Nullable T def) throws SerializationException {
+ public final ValueReference, N> referenceTo(final Type type,
+ final NodePath path, final @Nullable Object def) throws SerializationException {
+ return new ValueReferenceImpl<>(this, path, type, def);
+ }
+
+ @Override
+ public final ValueReference referenceTo(final TypeToken type, final NodePath path, final @Nullable T def) throws SerializationException {
return new ValueReferenceImpl<>(this, path, type, def);
}
diff --git a/core/src/main/java/org/spongepowered/configurate/reference/ValueReferenceImpl.java b/core/src/main/java/org/spongepowered/configurate/reference/ValueReferenceImpl.java
index f644b79c7..1eee698b9 100644
--- a/core/src/main/java/org/spongepowered/configurate/reference/ValueReferenceImpl.java
+++ b/core/src/main/java/org/spongepowered/configurate/reference/ValueReferenceImpl.java
@@ -30,6 +30,7 @@
import org.spongepowered.configurate.serialize.TypeSerializer;
import org.spongepowered.configurate.util.UnmodifiableCollections;
+import java.lang.reflect.Type;
import java.util.concurrent.Executor;
import java.util.function.Function;
@@ -38,18 +39,19 @@ class ValueReferenceImpl<@Nullable T, N extends ScopedConfigurationNode> impl
// Information about the reference
private final ManualConfigurationReference root;
private final NodePath path;
- private final TypeToken type;
+ private final Type type;
private final TypeSerializer serializer;
private final Publisher.Cached<@Nullable T> deserialized;
- ValueReferenceImpl(final ManualConfigurationReference root, final NodePath path, final TypeToken type,
+ @SuppressWarnings("unchecked")
+ ValueReferenceImpl(final ManualConfigurationReference root, final NodePath path, final Type type,
final @Nullable T def) throws SerializationException {
this.root = root;
this.path = path;
this.type = type;
- final @Nullable TypeSerializer serializer = root.node().options().serializers().get(type);
+ final @Nullable TypeSerializer serializer = (TypeSerializer) root.node().options().serializers().get(type);
if (serializer == null) {
- throw new SerializationException(this.path, type.getType(), "Unsupported type" + type);
+ throw new SerializationException(this.path, type, "Unsupported type" + type);
}
this.serializer = serializer;
@@ -63,19 +65,24 @@ class ValueReferenceImpl<@Nullable T, N extends ScopedConfigurationNode> impl
}).cache(deserializedValueFrom(root.node(), def));
}
+ ValueReferenceImpl(final ManualConfigurationReference root, final NodePath path, final TypeToken type,
+ final @Nullable T def) throws SerializationException {
+ this(root, path, type.getType(), def);
+ }
+
ValueReferenceImpl(final ManualConfigurationReference root, final NodePath path, final Class type,
final @Nullable T def) throws SerializationException {
- this(root, path, TypeToken.get(type), def);
+ this(root, path, (Type) type, def);
}
private @Nullable T deserializedValueFrom(final N parent, final @Nullable T defaultVal) throws SerializationException {
final N node = parent.node(this.path);
if (!node.virtual()) {
- return this.serializer.deserialize(this.type.getType(), node);
+ return this.serializer.deserialize(this.type, node);
}
- final @Nullable T defaultOrEmpty = defaultVal == null ? this.serializer.emptyValue(this.type.getType(), node.options()) : defaultVal;
+ final @Nullable T defaultOrEmpty = defaultVal == null ? this.serializer.emptyValue(this.type, node.options()) : defaultVal;
if (node.options().shouldCopyDefaults()) {
- this.serializer.serialize(this.type.getType(), defaultOrEmpty, node);
+ this.serializer.serialize(this.type, defaultOrEmpty, node);
}
return defaultOrEmpty;
}
@@ -88,7 +95,7 @@ class ValueReferenceImpl<@Nullable T, N extends ScopedConfigurationNode> impl
@Override
public boolean set(final @Nullable T value) {
try {
- this.serializer.serialize(this.type.getType(), value, node());
+ this.serializer.serialize(this.type, value, node());
this.deserialized.submit(value);
return true;
} catch (final SerializationException e) {
@@ -113,7 +120,7 @@ public boolean setAndSave(final @Nullable T value) {
@Override
public Publisher setAndSaveAsync(final @Nullable T value) {
return Publisher.execute(() -> {
- this.serializer.serialize(this.type.getType(), value, node());
+ this.serializer.serialize(this.type, value, node());
this.deserialized.submit(value);
this.root.save();
return true;
@@ -135,7 +142,7 @@ public Publisher updateAsync(final Function<@Nullable T, ? extends T> a
return Publisher.execute(() -> {
final @Nullable T orig = get();
final T updated = action.apply(orig);
- this.serializer.serialize(this.type.getType(), updated, node());
+ this.serializer.serialize(this.type, updated, node());
this.deserialized.submit(updated);
this.root.save();
return true;
From 62b61fcbbba763beb661f5d85568727c7dfb5f1f Mon Sep 17 00:00:00 2001
From: NichtStudioCode <51272202+NichtStudioCode@users.noreply.github.com>
Date: Mon, 24 Jul 2023 13:35:52 +0200
Subject: [PATCH 4/5] Add extension functions for KType and use
kotlin.reflect.typeOf
---
.../configurate/kotlin/ObjectMapping.kt | 7 +-
.../extensions/ConfigurationNodeExtensions.kt | 87 +++++++++++++++++--
.../ConfigurationReferenceExtensions.kt | 9 +-
.../extensions/ObjectMapperExtensions.kt | 25 +++++-
4 files changed, 113 insertions(+), 15 deletions(-)
diff --git a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/ObjectMapping.kt b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/ObjectMapping.kt
index ecf2ccc41..f86515b5d 100644
--- a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/ObjectMapping.kt
+++ b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/ObjectMapping.kt
@@ -38,6 +38,8 @@ import org.spongepowered.configurate.objectmapping.FieldDiscoverer
import org.spongepowered.configurate.objectmapping.ObjectMapper
import org.spongepowered.configurate.objectmapping.ObjectMapper.Factory
import org.spongepowered.configurate.util.Types.combinedAnnotations
+import kotlin.reflect.jvm.javaType
+import kotlin.reflect.typeOf
private val dataClassMapperFactory =
ObjectMapper.factoryBuilder().addDiscoverer(DataClassFieldDiscoverer).build()
@@ -60,8 +62,9 @@ fun dataClassFieldDiscoverer(): FieldDiscoverer<*> {
}
/** Get an object mapper for the type [T] using the default object mapper factory */
+@Suppress("UNCHECKED_CAST")
inline fun objectMapper(): ObjectMapper {
- return objectMapperFactory()[typeTokenOf()]
+ return objectMapperFactory()[typeOf().javaType] as ObjectMapper
}
/** Get an object mapper bound to the instance of [T], resolving type parameters */
@@ -69,8 +72,6 @@ inline fun T.toNode(target: ConfigurationNode) {
return objectMapperFactory().get().save(this, target)
}
-@PublishedApi internal inline fun typeTokenOf() = object : TypeToken() {}
-
/**
* A field discoverer that gathers definitions from kotlin `data` classes.
*
diff --git a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationNodeExtensions.kt b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationNodeExtensions.kt
index 8ca9886e6..98d586e9e 100644
--- a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationNodeExtensions.kt
+++ b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationNodeExtensions.kt
@@ -16,12 +16,14 @@
*/
package org.spongepowered.configurate.kotlin.extensions
-import kotlin.reflect.KClass
import org.spongepowered.configurate.ConfigurationNode
import org.spongepowered.configurate.NodePath
import org.spongepowered.configurate.ScopedConfigurationNode
-import org.spongepowered.configurate.kotlin.typeTokenOf
import org.spongepowered.configurate.serialize.SerializationException
+import kotlin.reflect.KClass
+import kotlin.reflect.KType
+import kotlin.reflect.jvm.javaType
+import kotlin.reflect.typeOf
/**
* An implementation of `contains` that can traverse multiple levels in [path].
@@ -58,7 +60,7 @@ operator fun ConfigurationNode.contains(path: Any): Boolean {
*/
@Throws(SerializationException::class)
inline fun ConfigurationNode.get(): V? {
- return get(typeTokenOf())
+ return get(typeOf().javaType) as V?
}
/**
@@ -68,7 +70,7 @@ inline fun ConfigurationNode.get(): V? {
*/
@Throws(SerializationException::class)
inline fun ConfigurationNode.get(default: V): V {
- return get(typeTokenOf(), default)
+ return get(typeOf().javaType, default) as V
}
/**
@@ -98,6 +100,33 @@ fun ConfigurationNode.get(type: KClass, default: () -> T): T {
return get(type.java, default)
}
+/**
+ * Get a value from the receiver using the type parameter.
+ *
+ * @see ConfigurationNode.get
+ */
+fun ConfigurationNode.get(type: KType): Any? {
+ return get(type.javaType)
+}
+
+/**
+ * Get a value from the receiver using the type parameter.
+ *
+ * @see ConfigurationNode.get
+ */
+fun ConfigurationNode.get(type: KType, default: Any): Any {
+ return get(type.javaType, default)
+}
+
+/**
+ * Get a value from the receiver using the type parameter.
+ *
+ * @see ConfigurationNode.get
+ */
+fun ConfigurationNode.get(type: KType, default: () -> Any): Any {
+ return get(type.javaType, default)
+}
+
/**
* Get a value from the receiver using the type parameter.
*
@@ -105,7 +134,7 @@ fun ConfigurationNode.get(type: KClass, default: () -> T): T {
*/
@Throws(SerializationException::class)
inline fun ConfigurationNode.get(noinline default: () -> V): V {
- return get(typeTokenOf(), default)
+ return get(typeOf().javaType, default) as V
}
/**
@@ -115,7 +144,7 @@ inline fun ConfigurationNode.get(noinline default: () -> V): V {
*/
@Throws(SerializationException::class)
inline fun ConfigurationNode.typedSet(value: V?) {
- set(typeTokenOf(), value)
+ set(typeOf().javaType, value)
}
/**
@@ -136,6 +165,34 @@ fun ConfigurationNode.getList(type: KClass, default: List): List
return getList(type.java, default)
}
+/**
+ * Get a list value from the receiver using a Kotlin type.
+ *
+ * @see ConfigurationNode.getList
+ */
+fun ConfigurationNode.getList(type: KType): List<*>? {
+ return getList(type.javaType)
+}
+
+/**
+ * Get a list value from the receiver using a Kotlin type.
+ *
+ * @see ConfigurationNode.getList
+ */
+fun ConfigurationNode.getList(type: KType, default: List<*>): List<*> {
+ return getList(type.javaType, default)
+}
+
+/**
+ * Get a list value with element type [T] from the receiver.
+ *
+ * @see ConfigurationNode.getList
+ */
+@Suppress("UNCHECKED_CAST")
+inline fun ConfigurationNode.getList(default: List): List {
+ return getList(typeOf().javaType, default) as List
+}
+
/**
* Set a value on the receiver described by a kotlin class.
*
@@ -145,6 +202,15 @@ fun ConfigurationNode.set(type: KClass, value: T?): ConfigurationNo
return set(type.java, value)
}
+/**
+ * Set a value on the receiver described by a kotlin class.
+ *
+ * @see ConfigurationNode.set
+ */
+fun ConfigurationNode.set(type: KType, value: Any?): ConfigurationNode {
+ return set(type.javaType, value)
+}
+
/**
* Set a value on the receiver described by a kotlin class.
*
@@ -153,3 +219,12 @@ fun ConfigurationNode.set(type: KClass, value: T?): ConfigurationNo
fun > N.set(type: KClass, value: T?): N {
return set(type.java, value)
}
+
+/**
+ * Set a value on the receiver described by a kotlin class.
+ *
+ * @see ConfigurationNode.set
+ */
+fun > N.set(type: KType, value: T?): N {
+ return set(type.javaType, value)
+}
diff --git a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationReferenceExtensions.kt b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationReferenceExtensions.kt
index b2261d701..c57be3847 100644
--- a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationReferenceExtensions.kt
+++ b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ConfigurationReferenceExtensions.kt
@@ -18,20 +18,23 @@ package org.spongepowered.configurate.kotlin.extensions
import kotlinx.coroutines.flow.Flow
import org.spongepowered.configurate.ScopedConfigurationNode
-import org.spongepowered.configurate.kotlin.typeTokenOf
import org.spongepowered.configurate.reference.ConfigurationReference
import org.spongepowered.configurate.reference.ValueReference
+import kotlin.reflect.jvm.javaType
+import kotlin.reflect.typeOf
/** Create a flow with events for every refresh of a value backing this reference */
+@Suppress("UNCHECKED_CAST")
inline fun > ConfigurationReference.flowOf(
vararg path: Any
): Flow {
- return this.referenceTo(typeTokenOf(), *path).asFlow()
+ return (this.referenceTo(typeOf().javaType, *path) as ValueReference).asFlow()
}
/** Get a reference to the value of type [T] at [path]. */
+@Suppress("UNCHECKED_CAST")
inline fun > ConfigurationReference.referenceTo(
vararg path: Any
): ValueReference {
- return this.referenceTo(typeTokenOf(), *path)
+ return this.referenceTo(typeOf().javaType, *path) as ValueReference
}
diff --git a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ObjectMapperExtensions.kt b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ObjectMapperExtensions.kt
index 34beaed12..78d1bdb1d 100644
--- a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ObjectMapperExtensions.kt
+++ b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/ObjectMapperExtensions.kt
@@ -17,7 +17,6 @@
package org.spongepowered.configurate.kotlin.extensions
import kotlin.reflect.KClass
-import org.spongepowered.configurate.kotlin.typeTokenOf
import org.spongepowered.configurate.objectmapping.ObjectMapper
import org.spongepowered.configurate.objectmapping.ObjectMapper.Factory
import org.spongepowered.configurate.objectmapping.ObjectMapper.Factory.Builder
@@ -25,13 +24,25 @@ import org.spongepowered.configurate.objectmapping.meta.Constraint
import org.spongepowered.configurate.objectmapping.meta.Processor
import org.spongepowered.configurate.serialize.TypeSerializer
import org.spongepowered.configurate.serialize.TypeSerializerCollection
+import kotlin.reflect.KType
+import kotlin.reflect.jvm.javaType
+import kotlin.reflect.typeOf
/**
* Create an object mapper with the given [Factory] for objects of type [T], accepting parameterized
* types.
*/
+@Suppress("UNCHECKED_CAST")
inline fun Factory.get(): ObjectMapper {
- return get(typeTokenOf())
+ return get(typeOf().javaType) as ObjectMapper
+}
+
+/**
+ * Create an object mapper with the given [Factory] for objects of type [type], accepting parameterized
+ * types.
+ */
+fun Factory.get(type: KType): ObjectMapper<*> {
+ return get(type.javaType)
}
/**
@@ -46,8 +57,16 @@ fun Factory.get(type: KClass): ObjectMapper {
/**
* Get the appropriate [TypeSerializer] for the provided type [T], or null if none is applicable.
*/
+@Suppress("UNCHECKED_CAST")
inline fun TypeSerializerCollection.get(): TypeSerializer? {
- return get(typeTokenOf())
+ return get(typeOf().javaType) as TypeSerializer?
+}
+
+/**
+ * Get the appropriate [TypeSerializer] for the provided type [type], or null if none is applicable.
+ */
+fun TypeSerializerCollection.get(type: KType): TypeSerializer<*>? {
+ return get(type.javaType)
}
/**
From ba4aae25c492c00792254ed0cad1e046f06616d8 Mon Sep 17 00:00:00 2001
From: NichtStudioCode <51272202+NichtStudioCode@users.noreply.github.com>
Date: Mon, 24 Jul 2023 15:32:16 +0200
Subject: [PATCH 5/5] Add missing javadoc
---
.../reference/ConfigurationReference.java | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/core/src/main/java/org/spongepowered/configurate/reference/ConfigurationReference.java b/core/src/main/java/org/spongepowered/configurate/reference/ConfigurationReference.java
index 6d52a2e48..e65918fe9 100644
--- a/core/src/main/java/org/spongepowered/configurate/reference/ConfigurationReference.java
+++ b/core/src/main/java/org/spongepowered/configurate/reference/ConfigurationReference.java
@@ -272,6 +272,21 @@ default void set(final NodePath path, final TypeToken type, final @Nullab
this.node().node(path).set(type, value);
}
+ /**
+ * Create a reference to the node at the provided path. The value will be
+ * deserialized according to the provided {@link Type}.
+ *
+ * The returned reference will update with reloads of and changes to the
+ * value of the provided configuration. Any serialization errors encountered
+ * will be submitted to the {@link #errors()} stream.
+ *
+ * @param type the value's type
+ * @param path the path from the root node to the node containing the value
+ * @return a deserializing reference to the node at the given path
+ * @throws SerializationException if a type serializer could not be found
+ * for the provided type
+ * @since TODO: version
+ */
default ValueReference, N> referenceTo(final Type type, final Object... path) throws SerializationException {
return this.referenceTo(type, NodePath.of(path));
}