|
1 | 1 | package io.papermc.paper.configuration.mapping;
|
2 | 2 |
|
| 3 | +import io.leangen.geantyref.GenericTypeReflector; |
3 | 4 | import io.papermc.paper.configuration.ConfigurationPart;
|
4 | 5 | import io.papermc.paper.configuration.WorldConfiguration;
|
| 6 | +import java.lang.annotation.Annotation; |
5 | 7 | import java.lang.reflect.AnnotatedType;
|
6 | 8 | import java.lang.reflect.Field;
|
| 9 | +import java.util.ArrayList; |
7 | 10 | import java.util.Collections;
|
| 11 | +import java.util.LinkedHashMap; |
| 12 | +import java.util.List; |
8 | 13 | import java.util.Map;
|
| 14 | +import java.util.SequencedMap; |
| 15 | +import java.util.function.Supplier; |
9 | 16 | import org.jspecify.annotations.Nullable;
|
10 | 17 | import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
|
11 | 18 | import org.spongepowered.configurate.serialize.SerializationException;
|
12 | 19 |
|
13 | 20 | import static io.leangen.geantyref.GenericTypeReflector.erase;
|
| 21 | +import static java.util.Objects.requireNonNullElseGet; |
14 | 22 |
|
15 |
| -public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, Object>> { |
| 23 | +public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, DeserializedFieldInfo<?>>> { |
16 | 24 |
|
17 | 25 | private final InnerClassInstanceSupplier instanceSupplier;
|
18 | 26 | private final FieldDiscoverer<Map<Field, Object>> delegate;
|
| 27 | + private final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors; |
19 | 28 |
|
20 |
| - @SuppressWarnings("unchecked") |
21 |
| - public InnerClassFieldDiscoverer(final Map<Class<?>, Object> initialOverrides) { |
22 |
| - this.instanceSupplier = new InnerClassInstanceSupplier(initialOverrides); |
23 |
| - this.delegate = (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(this.instanceSupplier); |
| 29 | + private InnerClassFieldDiscoverer(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer<Map<Field, Object>> delegate, final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors) { |
| 30 | + this.instanceSupplier = instanceSupplier; |
| 31 | + this.delegate = delegate; |
| 32 | + this.fieldProcessors = fieldProcessors; |
24 | 33 | }
|
25 | 34 |
|
| 35 | + @SuppressWarnings({"unchecked", "rawtypes"}) |
26 | 36 | @Override
|
27 |
| - public @Nullable <V> InstanceFactory<Map<Field, Object>> discover(final AnnotatedType target, final FieldCollector<Map<Field, Object>, V> collector) throws SerializationException { |
| 37 | + public @Nullable <V> InstanceFactory<Map<Field, DeserializedFieldInfo<?>>> discover(final AnnotatedType target, final FieldCollector<Map<Field, DeserializedFieldInfo<?>>, V> collector) throws SerializationException { |
28 | 38 | final Class<?> clazz = erase(target.getType());
|
29 | 39 | if (ConfigurationPart.class.isAssignableFrom(clazz)) {
|
30 |
| - final FieldDiscoverer.@Nullable InstanceFactory<Map<Field, Object>> instanceFactoryDelegate = this.delegate.<V>discover(target, (name, type, annotations, deserializer, serializer) -> { |
31 |
| - if (!erase(type.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes |
32 |
| - collector.accept(name, type, annotations, deserializer, serializer); |
| 40 | + // we don't care about the returned instance factory, we just need to call it to collect fields |
| 41 | + final Object dummyInstance = this.delegate.<V>discover(target, (name, fieldType, container, deserializer, serializer) -> { |
| 42 | + if (!erase(fieldType.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes |
| 43 | + FieldProcessor<?> processor = null; |
| 44 | + processor: for (final Annotation annotation : container.getAnnotations()) { |
| 45 | + final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> definitions = this.fieldProcessors.get(annotation.annotationType()); |
| 46 | + if (definitions != null) { |
| 47 | + for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> def : definitions) { |
| 48 | + if (GenericTypeReflector.isSuperType(def.type().getType(), GenericTypeReflector.box(fieldType.getType()))) { |
| 49 | + processor = ((FieldProcessor.Factory)def.factory()).make(annotation, fieldType); |
| 50 | + break processor; |
| 51 | + } |
| 52 | + } |
| 53 | + } |
| 54 | + } |
| 55 | + final FieldProcessor<?> finalProcessor = processor; |
| 56 | + collector.accept( |
| 57 | + name, |
| 58 | + fieldType, |
| 59 | + container, |
| 60 | + (intermediate, newValue, implicitInitializer) -> { |
| 61 | + // we only create this map to collect the field, it should only ever have 1 entry |
| 62 | + final SequencedMap<Field, Object> map = new LinkedHashMap<>(); |
| 63 | + deserializer.accept(map, newValue, implicitInitializer); |
| 64 | + final Object deserializedValue; |
| 65 | + deserializedValue = requireNonNullElseGet(newValue, () -> new ImplicitProvider(implicitInitializer)); |
| 66 | + intermediate.put(map.firstEntry().getKey(), new DeserializedFieldInfo<>(fieldType, deserializedValue, finalProcessor)); |
| 67 | + }, |
| 68 | + serializer |
| 69 | + ); |
33 | 70 | }
|
34 | 71 | });
|
35 |
| - if (instanceFactoryDelegate instanceof MutableInstanceFactory<Map<Field, Object>> mutableInstanceFactoryDelegate) { |
36 |
| - return new InnerClassInstanceFactory(this.instanceSupplier, mutableInstanceFactoryDelegate, target); |
| 72 | + if (dummyInstance == null) { |
| 73 | + return null; |
37 | 74 | }
|
| 75 | + return new InnerClassInstanceFactory(this.instanceSupplier, target); |
38 | 76 | }
|
39 | 77 | return null;
|
40 | 78 | }
|
41 | 79 |
|
42 |
| - public static FieldDiscoverer<?> worldConfig(WorldConfiguration worldConfiguration) { |
| 80 | + record ImplicitProvider(Supplier<Object> provider) { |
| 81 | + } |
| 82 | + |
| 83 | + @SuppressWarnings("unchecked") |
| 84 | + private static InnerClassFieldDiscoverer create(final Map<Class<?>, Object> overrides, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) { |
| 85 | + final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> processors = new LinkedHashMap<>(); |
| 86 | + for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> definition : fieldProcessors) { |
| 87 | + processors.computeIfAbsent(definition.annotation(), k -> new ArrayList<>()).add(definition); |
| 88 | + } |
| 89 | + final InnerClassInstanceSupplier instanceSupplier = new InnerClassInstanceSupplier(overrides); |
| 90 | + return new InnerClassFieldDiscoverer(instanceSupplier, (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(instanceSupplier), processors); |
| 91 | + } |
| 92 | + |
| 93 | + public static FieldDiscoverer<?> worldConfig(final WorldConfiguration worldConfiguration, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) { |
43 | 94 | final Map<Class<?>, Object> overrides = Map.of(
|
44 | 95 | WorldConfiguration.class, worldConfiguration
|
45 | 96 | );
|
46 |
| - return new InnerClassFieldDiscoverer(overrides); |
| 97 | + return create(overrides, fieldProcessors); |
47 | 98 | }
|
48 | 99 |
|
49 |
| - public static FieldDiscoverer<?> globalConfig() { |
50 |
| - return new InnerClassFieldDiscoverer(Collections.emptyMap()); |
| 100 | + public static FieldDiscoverer<?> globalConfig(final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) { |
| 101 | + return create(Collections.emptyMap(), fieldProcessors); |
51 | 102 | }
|
52 | 103 | }
|
0 commit comments