mirror of
https://github.com/PaperMC/Paper.git
synced 2025-07-26 01:32:02 -07:00
Update to configurate 4.2.0 (#12869)
This commit is contained in:
@@ -154,8 +154,7 @@ dependencies {
|
||||
implementation("io.netty:netty-codec-haproxy:4.1.118.Final") // Add support for proxy protocol
|
||||
implementation("org.apache.logging.log4j:log4j-iostreams:2.24.1")
|
||||
implementation("org.ow2.asm:asm-commons:9.8")
|
||||
implementation("org.spongepowered:configurate-yaml:4.2.0-20250225.064233-199")
|
||||
implementation("org.spongepowered:configurate-core:4.2.0-20250225.064233-204") // Pinned dependency of above pinned yaml snapshot.
|
||||
implementation("org.spongepowered:configurate-yaml:4.2.0")
|
||||
|
||||
// Deps that were previously in the API but have now been moved here for backwards compat, eventually to be removed
|
||||
runtimeOnly("commons-lang:commons-lang:2.6")
|
||||
|
@@ -3,6 +3,7 @@ package io.papermc.paper.configuration;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.papermc.paper.FeatureHooks;
|
||||
import io.papermc.paper.configuration.constraint.Constraints;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.WriteKeyBack;
|
||||
import io.papermc.paper.configuration.type.number.DoubleOr;
|
||||
import io.papermc.paper.configuration.type.number.IntOr;
|
||||
import io.papermc.paper.util.sanitizer.ItemObfuscationBinding;
|
||||
@@ -28,7 +29,7 @@ import java.util.Set;
|
||||
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"})
|
||||
public class GlobalConfiguration extends ConfigurationPart {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): <insert changes here>
|
||||
static final int CURRENT_VERSION = 30; // (when you change the version, change the comment, so it conflicts on rebases): upgrade packet to use ids
|
||||
private static GlobalConfiguration instance;
|
||||
public static boolean isFirstStart = false;
|
||||
public static GlobalConfiguration get() {
|
||||
@@ -274,7 +275,7 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
public class PacketLimiter extends ConfigurationPart {
|
||||
public Component kickMessage = Component.translatable("disconnect.exceeded_packet_rate", NamedTextColor.RED);
|
||||
public PacketLimit allPackets = new PacketLimit(7.0, 500.0, PacketLimit.ViolateAction.KICK);
|
||||
public Map<Class<? extends Packet<?>>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP));
|
||||
public Map<@WriteKeyBack Class<? extends Packet<?>>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP));
|
||||
|
||||
@ConfigSerializable
|
||||
public record PacketLimit(@Required double interval, @Required double maxPacketRate, ViolateAction action) {
|
||||
|
@@ -5,21 +5,25 @@ import com.google.common.collect.Table;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
|
||||
import io.papermc.paper.configuration.mapping.Definition;
|
||||
import io.papermc.paper.configuration.mapping.FieldProcessor;
|
||||
import io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer;
|
||||
import io.papermc.paper.configuration.mapping.MergeMap;
|
||||
import io.papermc.paper.configuration.serializer.ComponentSerializer;
|
||||
import io.papermc.paper.configuration.serializer.EnumValueSerializer;
|
||||
import io.papermc.paper.configuration.serializer.NbtPathSerializer;
|
||||
import io.papermc.paper.configuration.serializer.PacketClassSerializer;
|
||||
import io.papermc.paper.configuration.serializer.ServerboundPacketClassSerializer;
|
||||
import io.papermc.paper.configuration.serializer.ResourceLocationSerializer;
|
||||
import io.papermc.paper.configuration.serializer.StringRepresentableSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.FastutilMapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.TableSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.TableSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.FastutilMapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.MapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer;
|
||||
import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer;
|
||||
import io.papermc.paper.configuration.transformation.Transformations;
|
||||
import io.papermc.paper.configuration.transformation.global.LegacyPaperConfig;
|
||||
import io.papermc.paper.configuration.transformation.global.versioned.V29_LogIPs;
|
||||
import io.papermc.paper.configuration.transformation.global.versioned.V30_PacketIds;
|
||||
import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration;
|
||||
import io.papermc.paper.configuration.transformation.world.LegacyPaperWorldConfig;
|
||||
import io.papermc.paper.configuration.transformation.world.versioned.V29_ZeroWorldHeight;
|
||||
@@ -41,10 +45,12 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
@@ -196,7 +202,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
}
|
||||
|
||||
private static ObjectMapper.Factory.Builder defaultGlobalFactoryBuilder(ObjectMapper.Factory.Builder builder) {
|
||||
return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig());
|
||||
return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig(defaultFieldProcessors()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -209,7 +215,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
return options
|
||||
.header(GLOBAL_HEADER)
|
||||
.serializers(builder -> builder
|
||||
.register(new PacketClassSerializer())
|
||||
.register(new ServerboundPacketClassSerializer())
|
||||
.register(new RegistryValueSerializer<>(new TypeToken<DataComponentType<?>>() {}, registryAccess, Registries.DATA_COMPONENT_TYPE, false))
|
||||
);
|
||||
}
|
||||
@@ -232,7 +238,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
return super.createWorldObjectMapperFactoryBuilder(contextMap)
|
||||
.addNodeResolver(new RequiresSpigotInitialization.Factory(contextMap.require(SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get()))
|
||||
.addNodeResolver(new NestedSetting.Factory())
|
||||
.addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap)));
|
||||
.addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap), defaultFieldProcessors()));
|
||||
}
|
||||
|
||||
private static WorldConfiguration createWorldConfigInstance(ContextMap contextMap) {
|
||||
@@ -291,6 +297,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
|
||||
final ConfigurationTransformation.VersionedBuilder versionedBuilder = Transformations.versionedBuilder();
|
||||
V29_LogIPs.apply(versionedBuilder);
|
||||
V30_PacketIds.apply(versionedBuilder);
|
||||
// ADD FUTURE VERSIONED TRANSFORMS TO versionedBuilder HERE
|
||||
versionedBuilder.build().apply(node);
|
||||
}
|
||||
@@ -334,6 +341,12 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Definition<? extends Annotation, ?, ? extends FieldProcessor.Factory<?, ?>>> defaultFieldProcessors() {
|
||||
return List.of(
|
||||
MergeMap.DEFINITION
|
||||
);
|
||||
}
|
||||
|
||||
private static ContextMap createWorldContextMap(ServerLevel level) {
|
||||
return createWorldContextMap(level.levelStorageAccess.levelDirectory.path(), level.serverLevelData.getLevelName(), level.dimension().location(), level.spigotConfig, level.registryAccess(), level.getGameRules());
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import io.papermc.paper.configuration.legacy.MaxEntityCollisionsInitializer;
|
||||
import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
|
||||
import io.papermc.paper.configuration.mapping.MergeMap;
|
||||
import io.papermc.paper.configuration.serializer.NbtPathSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.ThrowExceptions;
|
||||
import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration;
|
||||
import io.papermc.paper.configuration.type.BooleanOrDefault;
|
||||
import io.papermc.paper.configuration.type.DespawnRange;
|
||||
@@ -193,15 +193,14 @@ public class WorldConfiguration extends ConfigurationPart {
|
||||
}
|
||||
}
|
||||
|
||||
@MapSerializer.ThrowExceptions
|
||||
public Reference2ObjectMap<EntityType<?>, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> {
|
||||
public @ThrowExceptions Reference2ObjectMap<EntityType<?>, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> {
|
||||
map.put(EntityType.SNOWBALL, IntOr.Disabled.DISABLED);
|
||||
map.put(EntityType.LLAMA_SPIT, IntOr.Disabled.DISABLED);
|
||||
});
|
||||
|
||||
@PostProcess
|
||||
public void precomputeDespawnDistances() throws SerializationException {
|
||||
for (Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) {
|
||||
for (final Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) {
|
||||
final MobCategory category = entry.getKey();
|
||||
final DespawnRangePair range = entry.getValue();
|
||||
range.hard().preComputed(category.getDespawnDistance(), category.getSerializedName());
|
||||
|
@@ -0,0 +1,11 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public record Definition<A extends Annotation, T, F>(Class<A> annotation, TypeToken<T> type, F factory) {
|
||||
|
||||
public Definition(final Class<A> annotation, final Class<T> type, final F factory) {
|
||||
this(annotation, TypeToken.get(type), factory);
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
public record DeserializedFieldInfo<V>(AnnotatedType fieldType, Object deserializedValue, @Nullable FieldProcessor<V> processor) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public @Nullable V runProcessor(final @Nullable Object valueInField, final @Nullable Object deserializedValue) throws SerializationException {
|
||||
checkState(this.processor != null, "processor is null");
|
||||
return this.processor.process(this.fieldType, (V) deserializedValue, (V) valueInField);
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public interface FieldProcessor<V> {
|
||||
|
||||
@Nullable V process(final AnnotatedType target, @Nullable V deserializedValue, @Nullable V valueInField) throws SerializationException;
|
||||
|
||||
interface Factory<A extends Annotation, T> {
|
||||
|
||||
FieldProcessor<T> make(A data, AnnotatedType annotatedType);
|
||||
}
|
||||
}
|
@@ -1,52 +1,103 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import io.papermc.paper.configuration.ConfigurationPart;
|
||||
import io.papermc.paper.configuration.WorldConfiguration;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SequencedMap;
|
||||
import java.util.function.Supplier;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||
import static java.util.Objects.requireNonNullElseGet;
|
||||
|
||||
public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, Object>> {
|
||||
public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, DeserializedFieldInfo<?>>> {
|
||||
|
||||
private final InnerClassInstanceSupplier instanceSupplier;
|
||||
private final FieldDiscoverer<Map<Field, Object>> delegate;
|
||||
private final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public InnerClassFieldDiscoverer(final Map<Class<?>, Object> initialOverrides) {
|
||||
this.instanceSupplier = new InnerClassInstanceSupplier(initialOverrides);
|
||||
this.delegate = (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(this.instanceSupplier);
|
||||
private InnerClassFieldDiscoverer(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer<Map<Field, Object>> delegate, final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors) {
|
||||
this.instanceSupplier = instanceSupplier;
|
||||
this.delegate = delegate;
|
||||
this.fieldProcessors = fieldProcessors;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public @Nullable <V> InstanceFactory<Map<Field, Object>> discover(final AnnotatedType target, final FieldCollector<Map<Field, Object>, V> collector) throws SerializationException {
|
||||
public @Nullable <V> InstanceFactory<Map<Field, DeserializedFieldInfo<?>>> discover(final AnnotatedType target, final FieldCollector<Map<Field, DeserializedFieldInfo<?>>, V> collector) throws SerializationException {
|
||||
final Class<?> clazz = erase(target.getType());
|
||||
if (ConfigurationPart.class.isAssignableFrom(clazz)) {
|
||||
final FieldDiscoverer.@Nullable InstanceFactory<Map<Field, Object>> instanceFactoryDelegate = this.delegate.<V>discover(target, (name, type, annotations, deserializer, serializer) -> {
|
||||
if (!erase(type.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes
|
||||
collector.accept(name, type, annotations, deserializer, serializer);
|
||||
// we don't care about the returned instance factory, we just need to call it to collect fields
|
||||
final Object dummyInstance = this.delegate.<V>discover(target, (name, fieldType, container, deserializer, serializer) -> {
|
||||
if (!erase(fieldType.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes
|
||||
FieldProcessor<?> processor = null;
|
||||
processor: for (final Annotation annotation : container.getAnnotations()) {
|
||||
final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> definitions = this.fieldProcessors.get(annotation.annotationType());
|
||||
if (definitions != null) {
|
||||
for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> def : definitions) {
|
||||
if (GenericTypeReflector.isSuperType(def.type().getType(), GenericTypeReflector.box(fieldType.getType()))) {
|
||||
processor = ((FieldProcessor.Factory)def.factory()).make(annotation, fieldType);
|
||||
break processor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final FieldProcessor<?> finalProcessor = processor;
|
||||
collector.accept(
|
||||
name,
|
||||
fieldType,
|
||||
container,
|
||||
(intermediate, newValue, implicitInitializer) -> {
|
||||
// we only create this map to collect the field, it should only ever have 1 entry
|
||||
final SequencedMap<Field, Object> map = new LinkedHashMap<>();
|
||||
deserializer.accept(map, newValue, implicitInitializer);
|
||||
final Object deserializedValue;
|
||||
deserializedValue = requireNonNullElseGet(newValue, () -> new ImplicitProvider(implicitInitializer));
|
||||
intermediate.put(map.firstEntry().getKey(), new DeserializedFieldInfo<>(fieldType, deserializedValue, finalProcessor));
|
||||
},
|
||||
serializer
|
||||
);
|
||||
}
|
||||
});
|
||||
if (instanceFactoryDelegate instanceof MutableInstanceFactory<Map<Field, Object>> mutableInstanceFactoryDelegate) {
|
||||
return new InnerClassInstanceFactory(this.instanceSupplier, mutableInstanceFactoryDelegate, target);
|
||||
if (dummyInstance == null) {
|
||||
return null;
|
||||
}
|
||||
return new InnerClassInstanceFactory(this.instanceSupplier, target);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FieldDiscoverer<?> worldConfig(WorldConfiguration worldConfiguration) {
|
||||
record ImplicitProvider(Supplier<Object> provider) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static InnerClassFieldDiscoverer create(final Map<Class<?>, Object> overrides, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
|
||||
final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> processors = new LinkedHashMap<>();
|
||||
for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> definition : fieldProcessors) {
|
||||
processors.computeIfAbsent(definition.annotation(), k -> new ArrayList<>()).add(definition);
|
||||
}
|
||||
final InnerClassInstanceSupplier instanceSupplier = new InnerClassInstanceSupplier(overrides);
|
||||
return new InnerClassFieldDiscoverer(instanceSupplier, (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(instanceSupplier), processors);
|
||||
}
|
||||
|
||||
public static FieldDiscoverer<?> worldConfig(final WorldConfiguration worldConfiguration, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
|
||||
final Map<Class<?>, Object> overrides = Map.of(
|
||||
WorldConfiguration.class, worldConfiguration
|
||||
);
|
||||
return new InnerClassFieldDiscoverer(overrides);
|
||||
return create(overrides, fieldProcessors);
|
||||
}
|
||||
|
||||
public static FieldDiscoverer<?> globalConfig() {
|
||||
return new InnerClassFieldDiscoverer(Collections.emptyMap());
|
||||
public static FieldDiscoverer<?> globalConfig(final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
|
||||
return create(Collections.emptyMap(), fieldProcessors);
|
||||
}
|
||||
}
|
||||
|
@@ -2,56 +2,68 @@ package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||
|
||||
final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> {
|
||||
final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory<Map<Field, DeserializedFieldInfo<?>>> {
|
||||
|
||||
private final InnerClassInstanceSupplier instanceSupplier;
|
||||
private final FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> fallback;
|
||||
private final AnnotatedType targetType;
|
||||
|
||||
InnerClassInstanceFactory(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> fallback, final AnnotatedType targetType) {
|
||||
InnerClassInstanceFactory(
|
||||
final InnerClassInstanceSupplier instanceSupplier,
|
||||
final AnnotatedType targetType
|
||||
) {
|
||||
this.instanceSupplier = instanceSupplier;
|
||||
this.fallback = fallback;
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Field, Object> begin() {
|
||||
return this.fallback.begin();
|
||||
public Map<Field, DeserializedFieldInfo<?>> begin() {
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void complete(final Object instance, final Map<Field, Object> intermediate) throws SerializationException {
|
||||
final Iterator<Map.Entry<Field, Object>> iter = intermediate.entrySet().iterator();
|
||||
try {
|
||||
while (iter.hasNext()) { // manually merge any mergeable maps
|
||||
Map.Entry<Field, Object> entry = iter.next();
|
||||
if (entry.getKey().isAnnotationPresent(MergeMap.class) && Map.class.isAssignableFrom(entry.getKey().getType()) && intermediate.get(entry.getKey()) instanceof Map<?, ?> map) {
|
||||
iter.remove();
|
||||
Map<Object, Object> existingMap = (Map<Object, Object>) entry.getKey().get(instance);
|
||||
if (existingMap != null) {
|
||||
existingMap.putAll(map);
|
||||
} else {
|
||||
entry.getKey().set(instance, entry.getValue());
|
||||
public void complete(final Object instance, final Map<Field, DeserializedFieldInfo<?>> intermediate) throws SerializationException {
|
||||
// modeled off of native ObjectFieldDiscoverer
|
||||
for (final Map.Entry<Field, DeserializedFieldInfo<?>> entry : intermediate.entrySet()) {
|
||||
final boolean hasProcessor = entry.getValue().processor() != null;
|
||||
try {
|
||||
final Object valueInField = entry.getKey().get(instance);
|
||||
if (entry.getValue().deserializedValue() instanceof InnerClassFieldDiscoverer.ImplicitProvider(final Supplier<Object> provider)) {
|
||||
Object newFieldValue = provider.get();
|
||||
if (hasProcessor) {
|
||||
newFieldValue = entry.getValue().runProcessor(valueInField, newFieldValue);
|
||||
}
|
||||
if (newFieldValue != null) {
|
||||
if (valueInField == null) {
|
||||
entry.getKey().set(instance, newFieldValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object newFieldValue = entry.getValue().deserializedValue();
|
||||
if (hasProcessor) {
|
||||
newFieldValue = entry.getValue().runProcessor(valueInField, newFieldValue);
|
||||
}
|
||||
entry.getKey().set(instance, newFieldValue);
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new SerializationException(this.targetType.getType(), e);
|
||||
} catch (final SerializationException ex) {
|
||||
ex.initType(entry.getValue().fieldType());
|
||||
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new SerializationException(this.targetType.getType(), e);
|
||||
}
|
||||
this.fallback.complete(instance, intermediate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object complete(final Map<Field, Object> intermediate) throws SerializationException {
|
||||
public Object complete(final Map<Field, DeserializedFieldInfo<?>> intermediate) throws SerializationException {
|
||||
final Object targetInstance = Objects.requireNonNull(this.instanceSupplier.instanceMap().get(erase(this.targetType.getType())), () -> this.targetType.getType() + " must already have an instance created");
|
||||
this.complete(targetInstance, intermediate);
|
||||
return targetInstance;
|
||||
@@ -59,6 +71,6 @@ final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstance
|
||||
|
||||
@Override
|
||||
public boolean canCreateInstances() {
|
||||
return this.fallback.canCreateInstances();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ final class InnerClassInstanceSupplier implements CheckedFunction<AnnotatedType,
|
||||
final Object instance = instanceSupplier.get();
|
||||
this.instanceMap.put(type, instance);
|
||||
return () -> instance;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new SerializationException(ConfigurationPart.class, target + " must be a valid ConfigurationPart", e);
|
||||
}
|
||||
} else {
|
||||
|
@@ -1,11 +1,20 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.papermc.paper.configuration.ConfigurationPart;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.MapSerializer;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
/**
|
||||
* For use in maps inside {@link ConfigurationPart}s that have default keys that shouldn't be removed by users
|
||||
@@ -17,4 +26,39 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MergeMap {
|
||||
|
||||
Logger LOGGER = LogUtils.getClassLogger();
|
||||
Definition<MergeMap, Map<?, ?>, Factory> DEFINITION = new Definition<>(MergeMap.class, MapSerializer.TYPE, new Factory());
|
||||
|
||||
/**
|
||||
* If marked as restricted, the field won't allow new keys beyond what
|
||||
* is already in the field when deserializing.
|
||||
*
|
||||
* @return True if restricted
|
||||
*/
|
||||
boolean restricted() default true;
|
||||
|
||||
final class Factory implements FieldProcessor.Factory<MergeMap, Map<?, ?>> {
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public FieldProcessor<Map<?, ?>> make(final MergeMap data, final AnnotatedType annotatedType) {
|
||||
return (target, deserializedValue, valueInField) -> {
|
||||
if (valueInField != null && deserializedValue != null) {
|
||||
if (data.restricted()) {
|
||||
final Set<?> invalidKeys = Sets.difference(deserializedValue.keySet(), valueInField.keySet()).immutableCopy();
|
||||
for (final Object invalidKey : invalidKeys) {
|
||||
LOGGER.error("The key {} is not allowed to be added to the field {}", invalidKey, target);
|
||||
}
|
||||
((Map) deserializedValue).keySet().removeAll(invalidKeys);
|
||||
}
|
||||
((Map) valueInField).putAll(deserializedValue);
|
||||
return valueInField;
|
||||
} else {
|
||||
checkState(!data.restricted() || valueInField != null, "If marked as restricted, field must have a value");
|
||||
return deserializedValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +1,25 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.function.Predicate;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ComponentSerializer extends ScalarSerializer<Component> {
|
||||
public class ComponentSerializer extends ScalarSerializer.Annotated<Component> {
|
||||
|
||||
public ComponentSerializer() {
|
||||
super(Component.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component deserialize(Type type, Object obj) throws SerializationException {
|
||||
public Component deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
return MiniMessage.miniMessage().deserialize(obj.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(Component component, Predicate<Class<?>> typeSupported) {
|
||||
return MiniMessage.miniMessage().serialize(component);
|
||||
protected Object serialize(final AnnotatedType type, final Component item, final Predicate<Class<?>> typeSupported) {
|
||||
return MiniMessage.miniMessage().serialize(item);
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,10 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import io.papermc.paper.configuration.type.EngineMode;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public final class EngineModeSerializer extends ScalarSerializer<EngineMode> {
|
||||
|
||||
@@ -14,11 +13,11 @@ public final class EngineModeSerializer extends ScalarSerializer<EngineMode> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EngineMode deserialize(Type type, Object obj) throws SerializationException {
|
||||
if (obj instanceof Integer id) {
|
||||
public EngineMode deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
if (obj instanceof final Integer id) {
|
||||
try {
|
||||
return EngineMode.valueOf(id);
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new SerializationException(id + " is not a valid id for type " + type + " for this node");
|
||||
}
|
||||
}
|
||||
@@ -27,7 +26,7 @@ public final class EngineModeSerializer extends ScalarSerializer<EngineMode> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(EngineMode item, Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final EngineMode item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.getId();
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
@@ -17,7 +17,7 @@ import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||
/**
|
||||
* Enum serializer that lists options if fails and accepts `-` as `_`.
|
||||
*/
|
||||
public class EnumValueSerializer extends ScalarSerializer<Enum<?>> {
|
||||
public class EnumValueSerializer extends ScalarSerializer.Annotated<Enum<?>> {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
|
||||
@@ -27,23 +27,23 @@ public class EnumValueSerializer extends ScalarSerializer<Enum<?>> {
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public @Nullable Enum<?> deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
public @Nullable Enum<?> deserialize(final AnnotatedType annotatedType, final Object obj) throws SerializationException {
|
||||
final String enumConstant = obj.toString();
|
||||
final Class<? extends Enum> typeClass = erase(type).asSubclass(Enum.class);
|
||||
final Class<? extends Enum> typeClass = erase(annotatedType.getType()).asSubclass(Enum.class);
|
||||
Enum<?> ret = EnumLookup.lookupEnum(typeClass, enumConstant);
|
||||
if (ret == null) {
|
||||
ret = EnumLookup.lookupEnum(typeClass, enumConstant.replace("-", "_"));
|
||||
}
|
||||
if (ret == null) {
|
||||
boolean longer = typeClass.getEnumConstants().length > 10;
|
||||
List<String> options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList();
|
||||
final boolean longer = typeClass.getEnumConstants().length > 10;
|
||||
final List<String> options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList();
|
||||
LOGGER.error("Invalid enum constant provided, expected one of [{}{}], but got {}", String.join(", ", options), longer ? ", ..." : "", enumConstant);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object serialize(final Enum<?> item, final Predicate<Class<?>> typeSupported) {
|
||||
public Object serialize(final AnnotatedType type, final Enum<?> item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.name();
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ package io.papermc.paper.configuration.serializer;
|
||||
import com.destroystokyo.paper.util.SneakyThrow;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
@@ -11,7 +11,7 @@ import net.minecraft.commands.arguments.NbtPathArgument;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public class NbtPathSerializer extends ScalarSerializer<NbtPathArgument.NbtPath> {
|
||||
public class NbtPathSerializer extends ScalarSerializer.Annotated<NbtPathArgument.NbtPath> {
|
||||
|
||||
public static final NbtPathSerializer SERIALIZER = new NbtPathSerializer();
|
||||
private static final NbtPathArgument DUMMY_ARGUMENT = new NbtPathArgument();
|
||||
@@ -20,23 +20,13 @@ public class NbtPathSerializer extends ScalarSerializer<NbtPathArgument.NbtPath>
|
||||
super(NbtPathArgument.NbtPath.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtPathArgument.NbtPath deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
return fromString(obj.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final NbtPathArgument.NbtPath item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.toString();
|
||||
}
|
||||
|
||||
public static List<NbtPathArgument.NbtPath> fromString(final List<String> tags) {
|
||||
List<NbtPathArgument.NbtPath> paths = new ArrayList<>();
|
||||
final List<NbtPathArgument.NbtPath> paths = new ArrayList<>();
|
||||
try {
|
||||
for (final String tag : tags) {
|
||||
paths.add(fromString(tag));
|
||||
}
|
||||
} catch (SerializationException ex) {
|
||||
} catch (final SerializationException ex) {
|
||||
SneakyThrow.sneaky(ex);
|
||||
}
|
||||
return List.copyOf(paths);
|
||||
@@ -45,8 +35,18 @@ public class NbtPathSerializer extends ScalarSerializer<NbtPathArgument.NbtPath>
|
||||
private static NbtPathArgument.NbtPath fromString(final String tag) throws SerializationException {
|
||||
try {
|
||||
return DUMMY_ARGUMENT.parse(new StringReader(tag));
|
||||
} catch (CommandSyntaxException e) {
|
||||
} catch (final CommandSyntaxException e) {
|
||||
throw new SerializationException(NbtPathArgument.NbtPath.class, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtPathArgument.NbtPath deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
return fromString(obj.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final AnnotatedType type, final NbtPathArgument.NbtPath item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -1,86 +0,0 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||
import io.papermc.paper.util.MappingEnvironment;
|
||||
import io.papermc.paper.util.ObfHelper;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@SuppressWarnings("Convert2Diamond")
|
||||
public final class PacketClassSerializer extends ScalarSerializer<Class<? extends Packet<?>>> implements MapSerializer.WriteBack {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
private static final TypeToken<Class<? extends Packet<?>>> TYPE = new TypeToken<Class<? extends Packet<?>>>() {};
|
||||
private static final List<String> SUBPACKAGES = List.of("game", "handshake", "login", "status");
|
||||
private static final BiMap<String, String> MOJANG_TO_OBF;
|
||||
|
||||
static {
|
||||
final ImmutableBiMap.Builder<String, String> builder = ImmutableBiMap.builder();
|
||||
final @Nullable Map<String, ObfHelper.ClassMapping> classMappingMap = ObfHelper.INSTANCE.mappingsByMojangName();
|
||||
if (classMappingMap != null) {
|
||||
classMappingMap.forEach((mojMap, classMapping) -> {
|
||||
if (mojMap.startsWith("net.minecraft.network.protocol.")) {
|
||||
builder.put(classMapping.mojangName(), classMapping.obfName());
|
||||
}
|
||||
});
|
||||
}
|
||||
MOJANG_TO_OBF = builder.build();
|
||||
}
|
||||
|
||||
public PacketClassSerializer() {
|
||||
super(TYPE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<? extends Packet<?>> deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
Class<?> packetClass = null;
|
||||
for (final String subpackage : SUBPACKAGES) {
|
||||
final String fullClassName = "net.minecraft.network.protocol." + subpackage + "." + obj;
|
||||
try {
|
||||
packetClass = Class.forName(fullClassName);
|
||||
break;
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
final String spigotClassName = MOJANG_TO_OBF.get(fullClassName);
|
||||
if (spigotClassName != null) {
|
||||
try {
|
||||
packetClass = Class.forName(spigotClassName);
|
||||
} catch (final ClassNotFoundException ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packetClass == null || !Packet.class.isAssignableFrom(packetClass)) {
|
||||
throw new SerializationException("Could not deserialize a packet from " + obj);
|
||||
}
|
||||
return (Class<? extends Packet<?>>) packetClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) {
|
||||
final String name = packetClass.getName();
|
||||
@Nullable String mojName = ObfHelper.INSTANCE.mappingsByMojangName() == null || !MappingEnvironment.reobf() ? name : MOJANG_TO_OBF.inverse().get(name); // if the mappings are null, running on moj-mapped server
|
||||
if (mojName == null && MOJANG_TO_OBF.containsKey(name)) {
|
||||
mojName = name;
|
||||
}
|
||||
if (mojName != null) {
|
||||
int pos = mojName.lastIndexOf('.');
|
||||
if (pos != -1 && pos != mojName.length() - 1) {
|
||||
return mojName.substring(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.error("Could not serialize {} into a mojang-mapped packet class name", packetClass);
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,12 +1,13 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public class ResourceLocationSerializer extends ScalarSerializer<ResourceLocation> {
|
||||
public class ResourceLocationSerializer extends ScalarSerializer.Annotated<ResourceLocation> {
|
||||
|
||||
public static final ScalarSerializer<ResourceLocation> INSTANCE = new ResourceLocationSerializer();
|
||||
|
||||
@@ -15,12 +16,12 @@ public class ResourceLocationSerializer extends ScalarSerializer<ResourceLocatio
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
public ResourceLocation deserialize(final AnnotatedType annotatedType, final Object obj) throws SerializationException {
|
||||
return ResourceLocation.read(obj.toString()).getOrThrow(s -> new SerializationException(ResourceLocation.class, s));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final ResourceLocation item, final Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType annotatedType, final ResourceLocation item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,118 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.PacketType;
|
||||
import net.minecraft.network.protocol.common.CommonPacketTypes;
|
||||
import net.minecraft.network.protocol.configuration.ConfigurationPacketTypes;
|
||||
import net.minecraft.network.protocol.cookie.CookiePacketTypes;
|
||||
import net.minecraft.network.protocol.game.GamePacketTypes;
|
||||
import net.minecraft.network.protocol.handshake.HandshakePacketTypes;
|
||||
import net.minecraft.network.protocol.login.LoginPacketTypes;
|
||||
import net.minecraft.network.protocol.ping.PingPacketTypes;
|
||||
import net.minecraft.network.protocol.status.StatusPacketTypes;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@SuppressWarnings("Convert2Diamond")
|
||||
public final class ServerboundPacketClassSerializer extends ScalarSerializer<Class<? extends Packet<?>>> {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
private static final TypeToken<Class<? extends Packet<?>>> TYPE = new TypeToken<Class<? extends Packet<?>>>() {};
|
||||
static final Set<Class<?>> PACKET_CLASS_HOLDERS = Set.of(
|
||||
PingPacketTypes.class,
|
||||
HandshakePacketTypes.class,
|
||||
StatusPacketTypes.class,
|
||||
LoginPacketTypes.class,
|
||||
ConfigurationPacketTypes.class,
|
||||
CommonPacketTypes.class,
|
||||
CookiePacketTypes.class,
|
||||
GamePacketTypes.class
|
||||
);
|
||||
private static final Map<ResourceLocation, PacketInfo> ID_TO_INFO;
|
||||
private static final Map<Class<?>, PacketInfo> CLASS_TO_INFO;
|
||||
|
||||
static {
|
||||
try {
|
||||
final ImmutableMap.Builder<ResourceLocation, PacketInfo> idBuilder = ImmutableMap.builder();
|
||||
final ImmutableMap.Builder<Class<?>, PacketInfo> classBuilder = ImmutableMap.builder();
|
||||
for (final Class<?> holder : PACKET_CLASS_HOLDERS) {
|
||||
for (final Field field : holder.getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(field.getModifiers()) || !Modifier.isFinal(field.getModifiers()) || !field.getType().equals(PacketType.class)) {
|
||||
continue;
|
||||
}
|
||||
final Type genericType = field.getGenericType();
|
||||
if (!(genericType instanceof final ParameterizedType parameterizedType)) {
|
||||
throw new RuntimeException("Unexpected generic type: " + genericType);
|
||||
}
|
||||
final PacketType<?> type = (PacketType<?>) field.get(null);
|
||||
if (type.flow() != PacketFlow.SERVERBOUND) {
|
||||
// we only care about serverbound for rate limiting
|
||||
continue;
|
||||
}
|
||||
final Class<?> packetClass = GenericTypeReflector.erase(parameterizedType.getActualTypeArguments()[0]);
|
||||
final PacketInfo info = new PacketInfo(packetClass.asSubclass(Packet.class), type);
|
||||
idBuilder.put(type.id(), info);
|
||||
classBuilder.put(packetClass, info);
|
||||
}
|
||||
}
|
||||
ID_TO_INFO = idBuilder.buildOrThrow();
|
||||
CLASS_TO_INFO = classBuilder.buildOrThrow();
|
||||
Preconditions.checkState(ID_TO_INFO.size() == 74, "Packet class map must have 74 entries");
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Could not create packet class map", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ServerboundPacketClassSerializer() {
|
||||
super(TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Packet<?>> deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
final ResourceLocation location = ResourceLocation.tryParse(obj.toString());
|
||||
if (location == null) {
|
||||
throw new SerializationException(ResourceLocation.class, "Could not deserialize a packet from " + obj);
|
||||
}
|
||||
final PacketInfo info = ID_TO_INFO.get(location);
|
||||
if (info == null) {
|
||||
throw new SerializationException("Could not deserialize a packet from " + obj);
|
||||
}
|
||||
return info.packetClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) {
|
||||
final PacketInfo info = CLASS_TO_INFO.get(packetClass);
|
||||
if (info == null) {
|
||||
LOGGER.error("Could not serialize {} into a packet identifier", packetClass);
|
||||
return null;
|
||||
} else {
|
||||
return info.type().id().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
record PacketInfo(Class<? extends Packet> clazz, PacketType<?> type) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<? extends Packet<?>> packetClass() {
|
||||
return (Class<? extends Packet<?>>) this.clazz;
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,6 +12,7 @@ import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public final class StringRepresentableSerializer extends ScalarSerializer<StringRepresentable> {
|
||||
|
||||
private static final Map<Type, Function<String, StringRepresentable>> TYPES = Collections.synchronizedMap(Map.ofEntries(
|
||||
createEntry(MobCategory.class)
|
||||
));
|
||||
@@ -24,20 +25,22 @@ public final class StringRepresentableSerializer extends ScalarSerializer<String
|
||||
return TYPES.containsKey(type);
|
||||
}
|
||||
|
||||
private static <E extends Enum<E> & StringRepresentable> Map.Entry<Type, Function<String, @Nullable StringRepresentable>> createEntry(Class<E> type) {
|
||||
return Map.entry(type, s -> {
|
||||
for (E value : type.getEnumConstants()) {
|
||||
if (value.getSerializedName().equals(s)) {
|
||||
return value;
|
||||
private static <E extends Enum<E> & StringRepresentable> Map.Entry<Type, Function<String, @Nullable StringRepresentable>> createEntry(final Class<E> type) {
|
||||
return Map.entry(
|
||||
type, s -> {
|
||||
for (final E value : type.getEnumConstants()) {
|
||||
if (value.getSerializedName().equals(s)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringRepresentable deserialize(Type type, Object obj) throws SerializationException {
|
||||
Function<String, StringRepresentable> function = TYPES.get(type);
|
||||
public StringRepresentable deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
final Function<String, StringRepresentable> function = TYPES.get(type);
|
||||
if (function == null) {
|
||||
throw new SerializationException(type + " isn't registered");
|
||||
}
|
||||
@@ -45,7 +48,7 @@ public final class StringRepresentableSerializer extends ScalarSerializer<String
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(StringRepresentable item, Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final StringRepresentable item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.getSerializedName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
package io.papermc.paper.configuration.serializer.collection;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
import io.leangen.geantyref.TypeFactory;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
@@ -15,33 +17,34 @@ import org.spongepowered.configurate.ConfigurationOptions;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
|
||||
public class TableSerializer implements TypeSerializer.Annotated<Table<?, ?, ?>> {
|
||||
private static final int ROW_TYPE_ARGUMENT_INDEX = 0;
|
||||
private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1;
|
||||
private static final int VALUE_TYPE_ARGUMENT_INDEX = 2;
|
||||
|
||||
@Override
|
||||
public Table<?, ?, ?> deserialize(final Type type, final ConfigurationNode node) throws SerializationException {
|
||||
public Table<?, ?, ?> deserialize(final AnnotatedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final Table<?, ?, ?> table = HashBasedTable.create();
|
||||
if (!node.empty() && node.isMap()) {
|
||||
this.deserialize0(table, (ParameterizedType) type, node);
|
||||
this.deserialize0(table, (AnnotatedParameterizedType) type, node);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <R, C, V> void deserialize0(final Table<R, C, V> table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
private <R, C, V> void deserialize0(final Table<R, C, V> table, final AnnotatedParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final AnnotatedType rowType = type.getAnnotatedActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType columnType = type.getAnnotatedActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType valueType = type.getAnnotatedActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
|
||||
final TypeSerializer<R> rowKeySerializer = (TypeSerializer<R>) node.options().serializers().get(rowType);
|
||||
if (rowKeySerializer == null) {
|
||||
throw new SerializationException("Could not find serializer for table row type " + rowType);
|
||||
}
|
||||
|
||||
final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType);
|
||||
final TypeSerializer<Map<C, V>> columnValueSerializer = (TypeSerializer<Map<C, V>>) node.options().serializers().get(mapType);
|
||||
final ParameterizedType mapType = (ParameterizedType) TypeFactory.parameterizedClass(Map.class, columnType.getType(), valueType.getType());
|
||||
final AnnotatedParameterizedType annotatedMapType = TypeFactory.parameterizedAnnotatedType(mapType, type.getAnnotations(), columnType.getAnnotations(), valueType.getAnnotations());
|
||||
final TypeSerializer<Map<C, V>> columnValueSerializer = (TypeSerializer<Map<C, V>>) node.options().serializers().get(annotatedMapType);
|
||||
if (columnValueSerializer == null) {
|
||||
throw new SerializationException("Could not find serializer for table column-value map " + type);
|
||||
}
|
||||
@@ -56,17 +59,21 @@ public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Type type, final @Nullable Table<?, ?, ?> table, final ConfigurationNode node) throws SerializationException {
|
||||
if (table != null) {
|
||||
this.serialize0(table, (ParameterizedType) type, node);
|
||||
public void serialize(
|
||||
final AnnotatedType type,
|
||||
final @Nullable Table<?, ?, ?> obj,
|
||||
final ConfigurationNode node
|
||||
) throws SerializationException {
|
||||
if (obj != null) {
|
||||
this.serialize0(obj, (AnnotatedParameterizedType) type, node);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private <R, C, V> void serialize0(final Table<R, C, V> table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
private <R, C, V> void serialize0(final Table<R, C, V> table, final AnnotatedParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final AnnotatedType rowType = type.getAnnotatedActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType columnType = type.getAnnotatedActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType valueType = type.getAnnotatedActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
|
||||
final TypeSerializer rowKeySerializer = node.options().serializers().get(rowType);
|
||||
if (rowKeySerializer == null) {
|
||||
@@ -77,12 +84,14 @@ public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
|
||||
for (final R key : table.rowKeySet()) {
|
||||
rowKeySerializer.serialize(rowType, key, rowKeyNode.set(key));
|
||||
final Object keyObj = Objects.requireNonNull(rowKeyNode.raw());
|
||||
node.node(keyObj).set(TypeFactory.parameterizedClass(Map.class, columnType, valueType), table.row(key));
|
||||
final ParameterizedType mapType = (ParameterizedType) TypeFactory.parameterizedClass(Map.class, columnType.getType(), valueType.getType());
|
||||
final AnnotatedParameterizedType annotatedMapType = TypeFactory.parameterizedAnnotatedType(mapType, type.getAnnotations(), columnType.getAnnotations(), valueType.getAnnotations());
|
||||
node.node(keyObj).set(annotatedMapType, table.row(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Table<?, ?, ?> emptyValue(Type specificType, ConfigurationOptions options) {
|
||||
public @Nullable Table<?, ?, ?> emptyValue(final Type specificType, final ConfigurationOptions options) {
|
||||
return ImmutableTable.of();
|
||||
}
|
||||
}
|
@@ -1,8 +1,7 @@
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import io.leangen.geantyref.TypeFactory;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.ParameterizedType;
|
@@ -1,11 +1,9 @@
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -36,56 +34,54 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
private final boolean clearInvalids;
|
||||
private final TypeSerializer<Map<?, ?>> fallback;
|
||||
|
||||
public MapSerializer(boolean clearInvalids) {
|
||||
public MapSerializer(final boolean clearInvalids) {
|
||||
this.clearInvalids = clearInvalids;
|
||||
this.fallback = requireNonNull(TypeSerializerCollection.defaults().get(TYPE), "Could not find default Map<?, ?> serializer");
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ThrowExceptions {}
|
||||
|
||||
@Override
|
||||
public Map<?, ?> deserialize(AnnotatedType annotatedType, ConfigurationNode node) throws SerializationException {
|
||||
public Map<?, ?> deserialize(final AnnotatedType annotatedType, final ConfigurationNode node) throws SerializationException {
|
||||
if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
|
||||
return this.fallback.deserialize(annotatedType, node);
|
||||
}
|
||||
final Map<Object, Object> map = new LinkedHashMap<>();
|
||||
final Type type = annotatedType.getType();
|
||||
if (node.isMap()) {
|
||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
||||
if (!(annotatedType instanceof final AnnotatedParameterizedType annotatedParameterizedType)) {
|
||||
throw new SerializationException(type, "Raw types are not supported for collections");
|
||||
}
|
||||
if (parameterizedType.getActualTypeArguments().length != 2) {
|
||||
if (annotatedParameterizedType.getAnnotatedActualTypeArguments().length != 2) {
|
||||
throw new SerializationException(type, "Map expected two type arguments!");
|
||||
}
|
||||
final Type key = parameterizedType.getActualTypeArguments()[0];
|
||||
final Type value = parameterizedType.getActualTypeArguments()[1];
|
||||
final @Nullable TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final @Nullable TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
final AnnotatedType key = annotatedParameterizedType.getAnnotatedActualTypeArguments()[0];
|
||||
final AnnotatedType value = annotatedParameterizedType.getAnnotatedActualTypeArguments()[1];
|
||||
final TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
if (keySerializer == null) {
|
||||
throw new SerializationException(type, "No type serializer available for key type " + key);
|
||||
}
|
||||
if (valueSerializer == null) {
|
||||
throw new SerializationException(type, "No type serializer available for value type " + value);
|
||||
}
|
||||
final boolean writeKeyBack = key.isAnnotationPresent(WriteKeyBack.class);
|
||||
|
||||
final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options());
|
||||
final Set<Object> keysToClear = new HashSet<>();
|
||||
for (Map.Entry<Object, ? extends ConfigurationNode> ent : node.childrenMap().entrySet()) {
|
||||
final @Nullable Object deserializedKey = deserialize(key, keySerializer, "key", keyNode.set(ent.getKey()), node.path());
|
||||
final @Nullable Object deserializedValue = deserialize(value, valueSerializer, "value", ent.getValue(), ent.getValue().path());
|
||||
for (final Map.Entry<Object, ? extends ConfigurationNode> ent : node.childrenMap().entrySet()) {
|
||||
final Object deserializedKey = this.deserialize(key.getType(), keySerializer, "key", keyNode.set(ent.getKey()), node.path());
|
||||
final Object deserializedValue = this.deserialize(value.getType(), valueSerializer, "value", ent.getValue(), ent.getValue().path());
|
||||
if (deserializedKey == null || deserializedValue == null) {
|
||||
continue;
|
||||
}
|
||||
if (keySerializer instanceof WriteBack) {
|
||||
if (serialize(key, keySerializer, deserializedKey, "key", keyNode, node.path()) && !ent.getKey().equals(requireNonNull(keyNode.raw(), "Key must not be null!"))) {
|
||||
if (writeKeyBack) {
|
||||
if (this.serialize(key.getType(), keySerializer, deserializedKey, "key", keyNode, node.path()) && !ent.getKey().equals(requireNonNull(keyNode.raw(), "Key must not be null!"))) {
|
||||
keysToClear.add(ent.getKey());
|
||||
}
|
||||
}
|
||||
map.put(deserializedKey, deserializedValue);
|
||||
}
|
||||
if (keySerializer instanceof WriteBack) { // supports cleaning keys which deserialize to the same value
|
||||
for (Object keyToClear : keysToClear) {
|
||||
if (writeKeyBack) { // supports cleaning keys which deserialize to the same value
|
||||
for (final Object keyToClear : keysToClear) {
|
||||
node.node(keyToClear).raw(null);
|
||||
}
|
||||
}
|
||||
@@ -93,10 +89,10 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
return map;
|
||||
}
|
||||
|
||||
private @Nullable Object deserialize(Type type, TypeSerializer<?> serializer, String mapPart, ConfigurationNode node, NodePath path) {
|
||||
private @Nullable Object deserialize(final Type type, final TypeSerializer<?> serializer, final String mapPart, final ConfigurationNode node, final NodePath path) {
|
||||
try {
|
||||
return serializer.deserialize(type, node);
|
||||
} catch (SerializationException ex) {
|
||||
} catch (final SerializationException ex) {
|
||||
ex.initPath(node::path);
|
||||
LOGGER.error("Could not deserialize {} {} into {} at {}: {}", mapPart, node.raw(), type, path, ex.rawMessage());
|
||||
}
|
||||
@@ -104,22 +100,22 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(AnnotatedType annotatedType, @Nullable Map<?, ?> obj, ConfigurationNode node) throws SerializationException {
|
||||
public void serialize(final AnnotatedType annotatedType, final @Nullable Map<?, ?> obj, final ConfigurationNode node) throws SerializationException {
|
||||
if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
|
||||
this.fallback.serialize(annotatedType, obj, node);
|
||||
return;
|
||||
}
|
||||
final Type type = annotatedType.getType();
|
||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
||||
if (!(annotatedType instanceof final AnnotatedParameterizedType annotatedParameterizedType)) {
|
||||
throw new SerializationException(type, "Raw types are not supported for collections");
|
||||
}
|
||||
if (parameterizedType.getActualTypeArguments().length != 2) {
|
||||
if (annotatedParameterizedType.getAnnotatedActualTypeArguments().length != 2) {
|
||||
throw new SerializationException(type, "Map expected two type arguments!");
|
||||
}
|
||||
final Type key = parameterizedType.getActualTypeArguments()[0];
|
||||
final Type value = parameterizedType.getActualTypeArguments()[1];
|
||||
final @Nullable TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final @Nullable TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
final AnnotatedType key = annotatedParameterizedType.getAnnotatedActualTypeArguments()[0];
|
||||
final AnnotatedType value = annotatedParameterizedType.getAnnotatedActualTypeArguments()[1];
|
||||
final TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
|
||||
if (keySerializer == null) {
|
||||
throw new SerializationException(type, "No type serializer available for key type " + key);
|
||||
@@ -135,22 +131,22 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
final Set<Object> unvisitedKeys;
|
||||
if (node.empty()) {
|
||||
node.raw(Collections.emptyMap());
|
||||
unvisitedKeys = Collections.emptySet();
|
||||
unvisitedKeys = new HashSet<>();
|
||||
} else {
|
||||
unvisitedKeys = new HashSet<>(node.childrenMap().keySet());
|
||||
}
|
||||
final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options());
|
||||
for (Map.Entry<?, ?> ent : obj.entrySet()) {
|
||||
if (!serialize(key, keySerializer, ent.getKey(), "key", keyNode, node.path())) {
|
||||
for (final Map.Entry<?, ?> ent : obj.entrySet()) {
|
||||
if (!this.serialize(key.getType(), keySerializer, ent.getKey(), "key", keyNode, node.path())) {
|
||||
continue;
|
||||
}
|
||||
final Object keyObj = requireNonNull(keyNode.raw(), "Key must not be null!");
|
||||
final ConfigurationNode child = node.node(keyObj);
|
||||
serialize(value, valueSerializer, ent.getValue(), "value", child, child.path());
|
||||
this.serialize(value.getType(), valueSerializer, ent.getValue(), "value", child, child.path());
|
||||
unvisitedKeys.remove(keyObj);
|
||||
}
|
||||
if (this.clearInvalids) {
|
||||
for (Object unusedChild : unvisitedKeys) {
|
||||
for (final Object unusedChild : unvisitedKeys) {
|
||||
node.removeChild(unusedChild);
|
||||
}
|
||||
}
|
||||
@@ -158,11 +154,11 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private boolean serialize(Type type, TypeSerializer serializer, Object object, String mapPart, ConfigurationNode node, NodePath path) {
|
||||
private boolean serialize(final Type type, final TypeSerializer serializer, final Object object, final String mapPart, final ConfigurationNode node, final NodePath path) {
|
||||
try {
|
||||
serializer.serialize(type, object, node);
|
||||
return true;
|
||||
} catch (SerializationException ex) {
|
||||
} catch (final SerializationException ex) {
|
||||
ex.initPath(node::path);
|
||||
LOGGER.error("Could not serialize {} {} from {} at {}: {}", mapPart, object, type, path, ex.rawMessage());
|
||||
}
|
||||
@@ -170,13 +166,11 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Map<?, ?> emptyValue(AnnotatedType specificType, ConfigurationOptions options) {
|
||||
public @Nullable Map<?, ?> emptyValue(final AnnotatedType specificType, final ConfigurationOptions options) {
|
||||
if (specificType.isAnnotationPresent(ThrowExceptions.class)) {
|
||||
return this.fallback.emptyValue(specificType, options);
|
||||
}
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public interface WriteBack { // marker interface
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ThrowExceptions {}
|
@@ -0,0 +1,10 @@
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WriteKeyBack {}
|
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package io.papermc.paper.configuration.serializer.collection;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
@@ -1,4 +0,0 @@
|
||||
@NullMarked
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
@@ -1,6 +1,7 @@
|
||||
package io.papermc.paper.configuration.serializer.registry;
|
||||
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.core.Registry;
|
||||
@@ -10,20 +11,30 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
abstract class RegistryEntrySerializer<T, R> extends ScalarSerializer<T> {
|
||||
abstract class RegistryEntrySerializer<T, R> extends ScalarSerializer.Annotated<T> {
|
||||
|
||||
private final RegistryAccess registryAccess;
|
||||
private final ResourceKey<? extends Registry<R>> registryKey;
|
||||
private final boolean omitMinecraftNamespace;
|
||||
|
||||
protected RegistryEntrySerializer(TypeToken<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<R>> registryKey, boolean omitMinecraftNamespace) {
|
||||
protected RegistryEntrySerializer(
|
||||
final TypeToken<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<R>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type);
|
||||
this.registryAccess = registryAccess;
|
||||
this.registryKey = registryKey;
|
||||
this.omitMinecraftNamespace = omitMinecraftNamespace;
|
||||
}
|
||||
|
||||
protected RegistryEntrySerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<R>> registryKey, boolean omitMinecraftNamespace) {
|
||||
protected RegistryEntrySerializer(
|
||||
final Class<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<R>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type);
|
||||
this.registryAccess = registryAccess;
|
||||
this.registryKey = registryKey;
|
||||
@@ -37,14 +48,14 @@ abstract class RegistryEntrySerializer<T, R> extends ScalarSerializer<T> {
|
||||
protected abstract T convertFromResourceKey(ResourceKey<R> key) throws SerializationException;
|
||||
|
||||
@Override
|
||||
public final T deserialize(Type type, Object obj) throws SerializationException {
|
||||
public final T deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
return this.convertFromResourceKey(this.deserializeKey(obj));
|
||||
}
|
||||
|
||||
protected abstract ResourceKey<R> convertToResourceKey(T value);
|
||||
|
||||
@Override
|
||||
protected final Object serialize(T item, Predicate<Class<?>> typeSupported) {
|
||||
protected final Object serialize(final AnnotatedType type, final T item, final Predicate<Class<?>> typeSupported) {
|
||||
final ResourceKey<R> key = this.convertToResourceKey(item);
|
||||
if (this.omitMinecraftNamespace && key.location().getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) {
|
||||
return key.location().getPath();
|
||||
|
@@ -13,22 +13,32 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
||||
public final class RegistryHolderSerializer<T> extends RegistryEntrySerializer<Holder<T>, T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public RegistryHolderSerializer(TypeToken<T> typeToken, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryHolderSerializer(
|
||||
final TypeToken<T> typeToken,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super((TypeToken<Holder<T>>) TypeToken.get(TypeFactory.parameterizedClass(Holder.class, typeToken.getType())), registryAccess, registryKey, omitMinecraftNamespace);
|
||||
}
|
||||
|
||||
public RegistryHolderSerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryHolderSerializer(
|
||||
final Class<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
this(TypeToken.get(type), registryAccess, registryKey, omitMinecraftNamespace);
|
||||
Preconditions.checkArgument(type.getTypeParameters().length == 0, "%s must have 0 type parameters", type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Holder<T> convertFromResourceKey(ResourceKey<T> key) throws SerializationException {
|
||||
protected Holder<T> convertFromResourceKey(final ResourceKey<T> key) throws SerializationException {
|
||||
return this.registry().get(key).orElseThrow(() -> new SerializationException("Missing holder in " + this.registry().key() + " with key " + key));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceKey<T> convertToResourceKey(Holder<T> value) {
|
||||
protected ResourceKey<T> convertToResourceKey(final Holder<T> value) {
|
||||
return value.unwrap().map(Function.identity(), r -> this.registry().getResourceKey(r).orElseThrow());
|
||||
}
|
||||
}
|
||||
|
@@ -11,16 +11,26 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
||||
*/
|
||||
public final class RegistryValueSerializer<T> extends RegistryEntrySerializer<T, T> {
|
||||
|
||||
public RegistryValueSerializer(TypeToken<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryValueSerializer(
|
||||
final TypeToken<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type, registryAccess, registryKey, omitMinecraftNamespace);
|
||||
}
|
||||
|
||||
public RegistryValueSerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryValueSerializer(
|
||||
final Class<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type, registryAccess, registryKey, omitMinecraftNamespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T convertFromResourceKey(ResourceKey<T> key) throws SerializationException {
|
||||
protected T convertFromResourceKey(final ResourceKey<T> key) throws SerializationException {
|
||||
final T value = this.registry().getValue(key);
|
||||
if (value == null) {
|
||||
throw new SerializationException("Missing value in " + this.registry() + " with key " + key.location());
|
||||
@@ -29,7 +39,7 @@ public final class RegistryValueSerializer<T> extends RegistryEntrySerializer<T,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceKey<T> convertToResourceKey(T value) {
|
||||
protected ResourceKey<T> convertToResourceKey(final T value) {
|
||||
return this.registry().getResourceKey(value).orElseThrow();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,67 @@
|
||||
package io.papermc.paper.configuration.transformation.global.versioned;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.NodePath;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public class V30_PacketIds implements TransformAction {
|
||||
|
||||
public static final V30_PacketIds INSTANCE = new V30_PacketIds();
|
||||
private static final int VERSION = 30;
|
||||
|
||||
private static final Gson GSON = new Gson();
|
||||
private static final Map<String, ResourceLocation> MOJANG_TO_ID;
|
||||
|
||||
static {
|
||||
final ImmutableMap.Builder<String, ResourceLocation> builder2 = ImmutableMap.builder();
|
||||
final InputStream input = V30_PacketIds.class.getResourceAsStream("/config-data/packet-limiter-upgrade-data.json");
|
||||
if (input == null) {
|
||||
throw new RuntimeException("Failed to load packet limiter upgrade data");
|
||||
}
|
||||
try (final Reader reader = new InputStreamReader(new BufferedInputStream(input))) {
|
||||
final JsonArray array = GSON.fromJson(reader, JsonArray.class);
|
||||
for (final JsonElement element : array) {
|
||||
final JsonObject obj = element.getAsJsonObject();
|
||||
builder2.put(obj.get("simple_class_name").getAsString(), ResourceLocation.parse(obj.get("id").getAsString()));
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException("Failed to load packet limiter upgrade data", e);
|
||||
}
|
||||
MOJANG_TO_ID = builder2.build();
|
||||
}
|
||||
|
||||
public static void apply(final ConfigurationTransformation.VersionedBuilder builder) {
|
||||
builder.addVersion(VERSION, ConfigurationTransformation.builder().addAction(path("packet-limiter", "overrides", ConfigurationTransformation.WILDCARD_OBJECT), INSTANCE).build());
|
||||
}
|
||||
|
||||
private V30_PacketIds() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) {
|
||||
final String oldClassName = path.get(path.size() - 1).toString();
|
||||
if (MOJANG_TO_ID.containsKey(oldClassName)) {
|
||||
return path.with(path.size() - 1, MOJANG_TO_ID.get(oldClassName).toString()).array();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package io.papermc.paper.configuration.type;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
@@ -9,38 +9,38 @@ import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public record BooleanOrDefault(@Nullable Boolean value) {
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final BooleanOrDefault USE_DEFAULT = new BooleanOrDefault(null);
|
||||
public static final ScalarSerializer<BooleanOrDefault> SERIALIZER = new Serializer();
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
|
||||
public boolean or(boolean fallback) {
|
||||
public boolean or(final boolean fallback) {
|
||||
return this.value == null ? fallback : this.value;
|
||||
}
|
||||
|
||||
private static final class Serializer extends ScalarSerializer<BooleanOrDefault> {
|
||||
private static final class Serializer extends ScalarSerializer.Annotated<BooleanOrDefault> {
|
||||
Serializer() {
|
||||
super(BooleanOrDefault.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanOrDefault deserialize(Type type, Object obj) throws SerializationException {
|
||||
if (obj instanceof String string) {
|
||||
public BooleanOrDefault deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
if (obj instanceof final String string) {
|
||||
if (DEFAULT_VALUE.equalsIgnoreCase(string)) {
|
||||
return USE_DEFAULT;
|
||||
}
|
||||
try {
|
||||
return new BooleanOrDefault(BooleanUtils.toBoolean(string.toLowerCase(Locale.ROOT), "true", "false"));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
throw new SerializationException(BooleanOrDefault.class, obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'", ex);
|
||||
}
|
||||
} else if (obj instanceof Boolean bool) {
|
||||
} else if (obj instanceof final Boolean bool) {
|
||||
return new BooleanOrDefault(bool);
|
||||
}
|
||||
throw new SerializationException(BooleanOrDefault.class, obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(BooleanOrDefault item, Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType type, final BooleanOrDefault item, final Predicate<Class<?>> typeSupported) {
|
||||
final Boolean value = item.value;
|
||||
if (value != null) {
|
||||
return value.toString();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package io.papermc.paper.configuration.type.number;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.function.DoublePredicate;
|
||||
import java.util.function.Function;
|
||||
@@ -20,17 +21,17 @@ public interface DoubleOr {
|
||||
}
|
||||
|
||||
record Default(OptionalDouble value) implements DoubleOr {
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final Default USE_DEFAULT = new Default(OptionalDouble.empty());
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final ScalarSerializer<Default> SERIALIZER = new Serializer<>(Default.class, Default::new, DEFAULT_VALUE, USE_DEFAULT);
|
||||
}
|
||||
|
||||
record Disabled(OptionalDouble value) implements DoubleOr {
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final Disabled DISABLED = new Disabled(OptionalDouble.empty());
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final ScalarSerializer<Disabled> SERIALIZER = new Serializer<>(Disabled.class, Disabled::new, DISABLED_VALUE, DISABLED);
|
||||
|
||||
public boolean test(DoublePredicate predicate) {
|
||||
public boolean test(final DoublePredicate predicate) {
|
||||
return this.value.isPresent() && predicate.test(this.value.getAsDouble());
|
||||
}
|
||||
|
||||
@@ -40,12 +41,12 @@ public interface DoubleOr {
|
||||
}
|
||||
|
||||
final class Serializer<T extends DoubleOr> extends OptionalNumSerializer<T, OptionalDouble> {
|
||||
Serializer(final Class<T> classOfT, final Function<OptionalDouble, T> factory, String emptySerializedValue, T emptyValue) {
|
||||
Serializer(final Class<T> classOfT, final Function<OptionalDouble, T> factory, final String emptySerializedValue, final T emptyValue) {
|
||||
super(classOfT, emptySerializedValue, emptyValue, OptionalDouble::empty, OptionalDouble::isEmpty, factory, double.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final T item, final Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType type, final T item, final Predicate<Class<?>> typeSupported) {
|
||||
final OptionalDouble value = item.value();
|
||||
if (value.isPresent()) {
|
||||
return value.getAsDouble();
|
||||
|
@@ -2,6 +2,7 @@ package io.papermc.paper.configuration.type.number;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntPredicate;
|
||||
@@ -28,17 +29,17 @@ public interface IntOr {
|
||||
}
|
||||
|
||||
record Default(OptionalInt value) implements IntOr {
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final Default USE_DEFAULT = new Default(OptionalInt.empty());
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final ScalarSerializer<Default> SERIALIZER = new Serializer<>(Default.class, Default::new, DEFAULT_VALUE, USE_DEFAULT);
|
||||
}
|
||||
|
||||
record Disabled(OptionalInt value) implements IntOr {
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final Disabled DISABLED = new Disabled(OptionalInt.empty());
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final ScalarSerializer<Disabled> SERIALIZER = new Serializer<>(Disabled.class, Disabled::new, DISABLED_VALUE, DISABLED);
|
||||
|
||||
public boolean test(IntPredicate predicate) {
|
||||
public boolean test(final IntPredicate predicate) {
|
||||
return this.value.isPresent() && predicate.test(this.value.getAsInt());
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ public interface IntOr {
|
||||
|
||||
final class Serializer<T extends IntOr> extends OptionalNumSerializer<T, OptionalInt> {
|
||||
|
||||
private Serializer(Class<T> classOfT, Function<OptionalInt, T> factory, String emptySerializedValue, T emptyValue) {
|
||||
private Serializer(final Class<T> classOfT, final Function<OptionalInt, T> factory, final String emptySerializedValue, final T emptyValue) {
|
||||
super(classOfT, emptySerializedValue, emptyValue, OptionalInt::empty, OptionalInt::isEmpty, factory, int.class);
|
||||
}
|
||||
|
||||
@@ -73,7 +74,7 @@ public interface IntOr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final T item, final Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType type, final T item, final Predicate<Class<?>> typeSupported) {
|
||||
final OptionalInt value = item.value();
|
||||
if (value.isPresent()) {
|
||||
return value.getAsInt();
|
||||
|
@@ -17,7 +17,15 @@ public abstract class OptionalNumSerializer<T, O> extends ScalarSerializer.Annot
|
||||
private final Function<O, T> factory;
|
||||
private final Class<?> number;
|
||||
|
||||
protected OptionalNumSerializer(final Class<T> classOfT, final String emptySerializedValue, final T emptyValue, final Supplier<O> empty, final Predicate<O> isEmpty, final Function<O, T> factory, final Class<?> number) {
|
||||
protected OptionalNumSerializer(
|
||||
final Class<T> classOfT,
|
||||
final String emptySerializedValue,
|
||||
final T emptyValue,
|
||||
final Supplier<O> empty,
|
||||
final Predicate<O> isEmpty,
|
||||
final Function<O, T> factory,
|
||||
final Class<?> number
|
||||
) {
|
||||
super(classOfT);
|
||||
this.emptySerializedValue = emptySerializedValue;
|
||||
this.emptyValue = emptyValue;
|
||||
@@ -30,7 +38,7 @@ public abstract class OptionalNumSerializer<T, O> extends ScalarSerializer.Annot
|
||||
@Override
|
||||
public final T deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
final O value;
|
||||
if (obj instanceof String string) {
|
||||
if (obj instanceof final String string) {
|
||||
if (this.emptySerializedValue.equalsIgnoreCase(string)) {
|
||||
value = this.empty.get();
|
||||
} else if (NumberUtils.isParsable(string)) {
|
||||
@@ -38,7 +46,7 @@ public abstract class OptionalNumSerializer<T, O> extends ScalarSerializer.Annot
|
||||
} else {
|
||||
throw new SerializationException("%s (%s) is not a(n) %s or '%s'".formatted(obj, type, this.number.getSimpleName(), this.emptySerializedValue));
|
||||
}
|
||||
} else if (obj instanceof Number num) {
|
||||
} else if (obj instanceof final Number num) {
|
||||
value = this.full(num);
|
||||
} else {
|
||||
throw new SerializationException("%s (%s) is not a(n) %s or '%s'".formatted(obj, type, this.number.getSimpleName(), this.emptySerializedValue));
|
||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user