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));
+ }
+
/**
* Create a reference to the node at the provided path. The value will be
* deserialized according to the provided TypeToken.
@@ -310,6 +330,25 @@ default ValueReference referenceTo(final TypeToken type, final Obje
default ValueReference referenceTo(final Class 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 +390,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;
diff --git a/extra/kotlin/build.gradle b/extra/kotlin/build.gradle
index ace4bdb02..8340b7337 100644
--- a/extra/kotlin/build.gradle
+++ b/extra/kotlin/build.gradle
@@ -23,12 +23,12 @@ dependencies {
}
kotlin {
- coreLibrariesVersion = "1.4.20"
+ coreLibrariesVersion = "1.8.20"
target {
compilations.configureEach {
kotlinOptions {
jvmTarget = "1.8"
- languageVersion = "1.4"
+ languageVersion = "1.8"
freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn", "-Xemit-jvm-type-annotations"]
}
}
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)
}
/**
diff --git a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/PublisherExtensions.kt b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/PublisherExtensions.kt
index 9b8cd42aa..bf36121d8 100644
--- a/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/PublisherExtensions.kt
+++ b/extra/kotlin/src/main/kotlin/org/spongepowered/configurate/kotlin/extensions/PublisherExtensions.kt
@@ -16,21 +16,19 @@
*/
package org.spongepowered.configurate.kotlin.extensions
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.channels.sendBlocking
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.runBlocking
import org.spongepowered.configurate.reactive.Publisher
import org.spongepowered.configurate.reactive.Subscriber
/** Given an [Publisher] instance, return a new [Flow] emitting values from the Flow */
-@OptIn(ExperimentalCoroutinesApi::class)
fun Publisher.asFlow(): Flow = callbackFlow {
val observer =
object : Subscriber {
override fun submit(item: V) {
- sendBlocking(item)
+ runBlocking { send(item) }
}
override fun onError(thrown: Throwable) {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2f5020936..2220c5f7b 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -25,7 +25,7 @@ junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref
stylecheck = "ca.stellardrift:stylecheck:0.2.1"
# Kotlin
-kotlin-coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
+kotlin-coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2"
kotlin-reflect = {module = "org.jetbrains.kotlin:kotlin-reflect"} # version from Kotlin BOM
# Core