From 96321dd6828e09c665062ce8e53e440deaf5f7bf Mon Sep 17 00:00:00 2001 From: Exlll Date: Sat, 6 Aug 2022 13:18:41 +0200 Subject: [PATCH] Add support for SerializeWith annotation --- .../de/exlll/configlib/SerializeWith.java | 63 +++++ .../exlll/configlib/SerializerSelector.java | 34 ++- .../de/exlll/configlib/TypeComponent.java | 2 +- .../de/exlll/configlib/TypeSerializer.java | 2 +- .../configlib/SerializerSelectorTest.java | 243 ++++++++++++++---- .../java/de/exlll/configlib/TestUtils.java | 13 + 6 files changed, 301 insertions(+), 56 deletions(-) create mode 100644 configlib-core/src/main/java/de/exlll/configlib/SerializeWith.java diff --git a/configlib-core/src/main/java/de/exlll/configlib/SerializeWith.java b/configlib-core/src/main/java/de/exlll/configlib/SerializeWith.java new file mode 100644 index 0000000..6b77108 --- /dev/null +++ b/configlib-core/src/main/java/de/exlll/configlib/SerializeWith.java @@ -0,0 +1,63 @@ +package de.exlll.configlib; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that the annotated element should be serialized with the given serializer. Serializers + * provided by this annotation take precedence over all other serializers. + *

+ * If the annotated element is an array, list, set, or map a nesting level can be set to apply the + * serializer not to the top-level type but to its elements. For maps, the serializer is applied to + * the values and not the keys. + *

+ * The following example shows how {@code nesting} can be used to apply the serializer at + * different levels. + * + *

+ * {@code
+ * // MyListSerializer is applied to 'list'
+ * @SerializeWith(serializer = MyListSerializer.class)
+ * List> list;
+ *
+ * // MySetSerializer is applied to the Set elements of 'list'
+ * @SerializeWith(serializer = MySetSerializer.class, nesting = 1)
+ * List> list;
+ *
+ * // MyStringSerializer is applied to the strings within the set elements of 'list'
+ * @SerializeWith(serializer = MyStringSerializer.class, nesting = 2)
+ * List> list;
+ *
+ * // MyMap0Serializer is applied to 'map'
+ * @SerializeWith(serializer = MyMap0Serializer.class)
+ * Map> map;
+ *
+ * // MyMap1Serializer is applied to the Map values of 'map'
+ * @SerializeWith(serializer = MyMap1Serializer.class, nesting = 1)
+ * Map> map;
+ *
+ * // MyDoubleSerializer is applied to the doubles within the nested values of 'map'
+ * @SerializeWith(serializer = MyDoubleSerializer.class, nesting = 2)
+ * Map> map;
+ * }
+ * 
+ */ +@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT}) +@Retention(RetentionPolicy.RUNTIME) +public @interface SerializeWith { + /** + * Returns the type of the serializer to be used. + * + * @return the type of serializer to use + */ + Class> serializer(); + + /** + * Returns the nesting level at which to apply the serializer. + * + * @return the nesting level + */ + int nesting() default 0; +} diff --git a/configlib-core/src/main/java/de/exlll/configlib/SerializerSelector.java b/configlib-core/src/main/java/de/exlll/configlib/SerializerSelector.java index 96e6e58..67bd7ba 100644 --- a/configlib-core/src/main/java/de/exlll/configlib/SerializerSelector.java +++ b/configlib-core/src/main/java/de/exlll/configlib/SerializerSelector.java @@ -50,12 +50,32 @@ final class SerializerSelector { Map.entry(URI.class, new UriSerializer()) ); private final ConfigurationProperties properties; + /** + * Holds the {@code SerializeWith} value of the last {@literal select}ed component. If the + * component is not annotated with {@code SerializeWith}, the value of this field is null. + */ + private SerializeWith serializeWith; + /** + * The {@code currentNesting} is used to determine the nesting of a type and is incremented each + * time the {@code selectForType} method is called. It is reset when {@code select} is called. + *

+ * For example, for a field {@code List>}, the nesting of {@code List} would be 0, + * the nesting of {@code Set} 1, and the nesting of {@code String} 2. + */ + private int currentNesting = -1; public SerializerSelector(ConfigurationProperties properties) { this.properties = requireNonNull(properties, "configuration properties"); } - public Serializer select(Type type) { + public Serializer select(TypeComponent component) { + this.currentNesting = -1; + this.serializeWith = component.annotation(SerializeWith.class); + return selectForType(component.genericType()); + } + + private Serializer selectForType(Type type) { + this.currentNesting++; final Serializer custom = selectCustomSerializer(type); if (custom != null) return custom; @@ -78,6 +98,8 @@ final class SerializerSelector { } private Serializer selectCustomSerializer(Type type) { + if ((serializeWith != null) && (currentNesting == serializeWith.nesting())) + return Reflect.callNoParamConstructor(serializeWith.serializer()); if (type instanceof Class cls) { if (properties.getSerializers().containsKey(cls)) return properties.getSerializers().get(cls); @@ -133,7 +155,7 @@ final class SerializerSelector { } else if (elementType == double.class) { return new PrimitiveDoubleArraySerializer(); } - var elementSerializer = select(elementType); + var elementSerializer = selectForType(elementType); var inputNulls = properties.inputNulls(); var outputNulls = properties.outputNulls(); return new ArraySerializer<>(elementType, elementSerializer, outputNulls, inputNulls); @@ -147,10 +169,10 @@ final class SerializerSelector { final var outputNulls = properties.outputNulls(); if (Reflect.isListType(rawType)) { - var elementSerializer = select(typeArgs[0]); + var elementSerializer = selectForType(typeArgs[0]); return new ListSerializer<>(elementSerializer, outputNulls, inputNulls); } else if (Reflect.isSetType(rawType)) { - var elementSerializer = select(typeArgs[0]); + var elementSerializer = selectForType(typeArgs[0]); return properties.serializeSetsAsLists() ? new SetAsListSerializer<>(elementSerializer, outputNulls, inputNulls) : new SetSerializer<>(elementSerializer, outputNulls, inputNulls); @@ -158,8 +180,8 @@ final class SerializerSelector { if ((typeArgs[0] instanceof Class cls) && (DEFAULT_SERIALIZERS.containsKey(cls) || Reflect.isEnumType(cls))) { - var keySerializer = select(typeArgs[0]); - var valSerializer = select(typeArgs[1]); + var keySerializer = selectForClass(cls); + var valSerializer = selectForType(typeArgs[1]); return new MapSerializer<>(keySerializer, valSerializer, outputNulls, inputNulls); } String msg = baseExceptionMessage(type) + diff --git a/configlib-core/src/main/java/de/exlll/configlib/TypeComponent.java b/configlib-core/src/main/java/de/exlll/configlib/TypeComponent.java index c3f5d7a..98f4178 100644 --- a/configlib-core/src/main/java/de/exlll/configlib/TypeComponent.java +++ b/configlib-core/src/main/java/de/exlll/configlib/TypeComponent.java @@ -14,7 +14,7 @@ import static de.exlll.configlib.Validator.requireNonNull; * * @param the type of the component */ -sealed interface TypeComponent { +interface TypeComponent { /** * Returns the component itself. * diff --git a/configlib-core/src/main/java/de/exlll/configlib/TypeSerializer.java b/configlib-core/src/main/java/de/exlll/configlib/TypeSerializer.java index 125fe68..19ef777 100644 --- a/configlib-core/src/main/java/de/exlll/configlib/TypeSerializer.java +++ b/configlib-core/src/main/java/de/exlll/configlib/TypeSerializer.java @@ -37,7 +37,7 @@ sealed abstract class TypeSerializer> try { return components().stream().collect(Collectors.toMap( TypeComponent::name, - component -> selector.select(component.genericType()) + selector::select )); } catch (StackOverflowError error) { String msg = "Recursive type definitions are not supported."; diff --git a/configlib-core/src/test/java/de/exlll/configlib/SerializerSelectorTest.java b/configlib-core/src/test/java/de/exlll/configlib/SerializerSelectorTest.java index b126457..dd3fded 100644 --- a/configlib-core/src/test/java/de/exlll/configlib/SerializerSelectorTest.java +++ b/configlib-core/src/test/java/de/exlll/configlib/SerializerSelectorTest.java @@ -4,6 +4,7 @@ import de.exlll.configlib.Serializers.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Mockito; import java.awt.Point; import java.io.File; @@ -28,6 +29,7 @@ import static de.exlll.configlib.TestUtils.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +@SuppressWarnings("unused") class SerializerSelectorTest { private static final SerializerSelector SELECTOR = new SerializerSelector( ConfigurationProperties.newBuilder().build() @@ -38,10 +40,21 @@ class SerializerSelectorTest { return ls.getGenericType(); } + private static TypeComponent comp(Type type) { + TypeComponent mock = Mockito.mock(TypeComponent.class); + Mockito.when(mock.genericType()).thenReturn(type); + return mock; + } + + private static TypeComponent comp(Class type, String fieldName) { + Field field = getField(type, fieldName); + return new TypeComponent.ConfigurationField(field); + } + @ParameterizedTest @ValueSource(classes = {boolean.class, Boolean.class}) void selectSerializerBoolean(Class cls) { - Serializer serializer = SELECTOR.select(cls); + Serializer serializer = SELECTOR.select(comp(cls)); assertThat(serializer, instanceOf(BooleanSerializer.class)); } @@ -52,99 +65,99 @@ class SerializerSelectorTest { float.class, Float.class, double.class, Double.class }) void selectSerializerNumber(Class cls) { - NumberSerializer serializer = (NumberSerializer) SELECTOR.select(cls); + NumberSerializer serializer = (NumberSerializer) SELECTOR.select(comp(cls)); assertThat(serializer.getNumberClass(), equalTo(cls)); } @ParameterizedTest @ValueSource(classes = {char.class, Character.class}) void selectSerializerChar(Class cls) { - Serializer serializer = SELECTOR.select(cls); + Serializer serializer = SELECTOR.select(comp(cls)); assertThat(serializer, instanceOf(CharacterSerializer.class)); } @Test void selectSerializerString() { - Serializer serializer = SELECTOR.select(String.class); + Serializer serializer = SELECTOR.select(comp(String.class)); assertThat(serializer, instanceOf(StringSerializer.class)); } @Test void selectSerializerBigInteger() { - Serializer serializer = SELECTOR.select(BigInteger.class); + Serializer serializer = SELECTOR.select(comp(BigInteger.class)); assertThat(serializer, instanceOf(BigIntegerSerializer.class)); } @Test void selectSerializerBigDecimal() { - Serializer serializer = SELECTOR.select(BigDecimal.class); + Serializer serializer = SELECTOR.select(comp(BigDecimal.class)); assertThat(serializer, instanceOf(BigDecimalSerializer.class)); } @Test void selectSerializerLocalDate() { - Serializer serializer = SELECTOR.select(LocalDate.class); + Serializer serializer = SELECTOR.select(comp(LocalDate.class)); assertThat(serializer, instanceOf(LocalDateSerializer.class)); } @Test void selectSerializerLocalTime() { - Serializer serializer = SELECTOR.select(LocalTime.class); + Serializer serializer = SELECTOR.select(comp(LocalTime.class)); assertThat(serializer, instanceOf(LocalTimeSerializer.class)); } @Test void selectSerializerLocalDateTime() { - Serializer serializer = SELECTOR.select(LocalDateTime.class); + Serializer serializer = SELECTOR.select(comp(LocalDateTime.class)); assertThat(serializer, instanceOf(LocalDateTimeSerializer.class)); } @Test void selectSerializerInstant() { - Serializer serializer = SELECTOR.select(Instant.class); + Serializer serializer = SELECTOR.select(comp(Instant.class)); assertThat(serializer, instanceOf(InstantSerializer.class)); } @Test void selectSerializerUuid() { - Serializer serializer = SELECTOR.select(UUID.class); + Serializer serializer = SELECTOR.select(comp(UUID.class)); assertThat(serializer, instanceOf(UuidSerializer.class)); } @Test void selectSerializerFile() { - Serializer serializer = SELECTOR.select(File.class); + Serializer serializer = SELECTOR.select(comp(File.class)); assertThat(serializer, instanceOf(FileSerializer.class)); } @Test void selectSerializerPath() { - Serializer serializer = SELECTOR.select(Path.class); + Serializer serializer = SELECTOR.select(comp(Path.class)); assertThat(serializer, instanceOf(PathSerializer.class)); } @Test void selectSerializerUrl() { - Serializer serializer = SELECTOR.select(URL.class); + Serializer serializer = SELECTOR.select(comp(URL.class)); assertThat(serializer, instanceOf(UrlSerializer.class)); } @Test void selectSerializerUri() { - Serializer serializer = SELECTOR.select(URI.class); + Serializer serializer = SELECTOR.select(comp(URI.class)); assertThat(serializer, instanceOf(UriSerializer.class)); } @Test void selectSerializerEnum() { enum E {} - EnumSerializer serializer = (EnumSerializer) SELECTOR.select(E.class); + EnumSerializer serializer = (EnumSerializer) SELECTOR.select(comp(E.class)); assertThat(serializer.getEnumCls(), equalTo(E.class)); } @Test void selectSerializerArray() { - var serializer = (ArraySerializer) SELECTOR.select(String[][].class); + var serializer = (ArraySerializer) SELECTOR.select(comp(String[][].class)); assertThat(serializer.getComponentType(), equalTo(String[].class)); var elementSerializer = (ArraySerializer) serializer.getElementSerializer(); @@ -154,49 +167,49 @@ class SerializerSelectorTest { @Test void selectSerializerPrimitiveBooleanArray() { - Serializer serializer = SELECTOR.select(boolean[].class); + Serializer serializer = SELECTOR.select(comp(boolean[].class)); assertThat(serializer, instanceOf(PrimitiveBooleanArraySerializer.class)); } @Test void selectSerializerPrimitiveCharacterArray() { - Serializer serializer = SELECTOR.select(char[].class); + Serializer serializer = SELECTOR.select(comp(char[].class)); assertThat(serializer, instanceOf(PrimitiveCharacterArraySerializer.class)); } @Test void selectSerializerPrimitiveByteArray() { - Serializer serializer = SELECTOR.select(byte[].class); + Serializer serializer = SELECTOR.select(comp(byte[].class)); assertThat(serializer, instanceOf(PrimitiveByteArraySerializer.class)); } @Test void selectSerializerPrimitiveShortArray() { - Serializer serializer = SELECTOR.select(short[].class); + Serializer serializer = SELECTOR.select(comp(short[].class)); assertThat(serializer, instanceOf(PrimitiveShortArraySerializer.class)); } @Test void selectSerializerPrimitiveIntegerArray() { - Serializer serializer = SELECTOR.select(int[].class); + Serializer serializer = SELECTOR.select(comp(int[].class)); assertThat(serializer, instanceOf(PrimitiveIntegerArraySerializer.class)); } @Test void selectSerializerPrimitiveLongArray() { - Serializer serializer = SELECTOR.select(long[].class); + Serializer serializer = SELECTOR.select(comp(long[].class)); assertThat(serializer, instanceOf(PrimitiveLongArraySerializer.class)); } @Test void selectSerializerPrimitiveFloatArray() { - Serializer serializer = SELECTOR.select(float[].class); + Serializer serializer = SELECTOR.select(comp(float[].class)); assertThat(serializer, instanceOf(PrimitiveFloatArraySerializer.class)); } @Test void selectSerializerPrimitiveDoubleArray() { - Serializer serializer = SELECTOR.select(double[].class); + Serializer serializer = SELECTOR.select(comp(double[].class)); assertThat(serializer, instanceOf(PrimitiveDoubleArraySerializer.class)); } @@ -206,14 +219,14 @@ class SerializerSelectorTest { class A { int i; } - var serializer = (ConfigurationSerializer) SELECTOR.select(A.class); + var serializer = (ConfigurationSerializer) SELECTOR.select(comp(A.class)); assertThat(serializer.getConfigurationType(), equalTo(A.class)); } @Test void selectSerializerRecord() { record R(int i) {} - var serializer = (RecordSerializer) SELECTOR.select(R.class); + var serializer = (RecordSerializer) SELECTOR.select(comp(R.class)); assertThat(serializer.getRecordType(), equalTo(R.class)); } @@ -221,14 +234,14 @@ class SerializerSelectorTest { void recordSerializerTakesPrecedenceOverConfigurationSerializer() { @Configuration record R(int i) {} - var serializer = (RecordSerializer) SELECTOR.select(R.class); + var serializer = (RecordSerializer) SELECTOR.select(comp(R.class)); assertThat(serializer.getRecordType(), equalTo(R.class)); } @Test void selectSerializerMissingType() { assertThrowsConfigurationException( - () -> SELECTOR.select(Object.class), + () -> SELECTOR.select(comp(Object.class)), "Missing serializer for type class java.lang.Object.\nEither annotate the type with " + "@Configuration or provide a custom serializer by adding it to the properties." ); @@ -240,7 +253,7 @@ class SerializerSelectorTest { .addSerializer(Point.class, POINT_SERIALIZER) .build(); SerializerSelector selector = new SerializerSelector(properties); - var pointSerializer = selector.select(Point.class); + var pointSerializer = selector.select(comp(Point.class)); assertThat(pointSerializer, sameInstance(POINT_SERIALIZER)); } @@ -250,7 +263,7 @@ class SerializerSelectorTest { .addSerializer(BigInteger.class, CUSTOM_BIG_INTEGER_SERIALIZER) .build(); SerializerSelector selector = new SerializerSelector(properties); - var bigIntegerSerializer = selector.select(BigInteger.class); + var bigIntegerSerializer = selector.select(comp(BigInteger.class)); assertThat(bigIntegerSerializer, instanceOf(TestUtils.CustomBigIntegerSerializer.class)); assertThat(bigIntegerSerializer, sameInstance(CUSTOM_BIG_INTEGER_SERIALIZER)); } @@ -261,7 +274,7 @@ class SerializerSelectorTest { .addSerializerByCondition(t -> t == Point.class, POINT_SERIALIZER) .build(); SerializerSelector selector = new SerializerSelector(properties); - var pointSerializer = selector.select(Point.class); + var pointSerializer = selector.select(comp(Point.class)); assertThat(pointSerializer, sameInstance(POINT_SERIALIZER)); } @@ -271,7 +284,7 @@ class SerializerSelectorTest { .addSerializerByCondition(t -> t == BigInteger.class, CUSTOM_BIG_INTEGER_SERIALIZER) .build(); SerializerSelector selector = new SerializerSelector(properties); - var bigIntegerSerializer = selector.select(BigInteger.class); + var bigIntegerSerializer = selector.select(comp(BigInteger.class)); assertThat(bigIntegerSerializer, instanceOf(TestUtils.CustomBigIntegerSerializer.class)); assertThat(bigIntegerSerializer, sameInstance(CUSTOM_BIG_INTEGER_SERIALIZER)); } @@ -285,7 +298,7 @@ class SerializerSelectorTest { .addSerializer(int.class, serializer2) .build(); SerializerSelector selector = new SerializerSelector(properties); - var serializer = selector.select(int.class); + var serializer = selector.select(comp(int.class)); assertThat(serializer, instanceOf(IdentifiableSerializer.class)); assertThat(serializer, sameInstance(serializer2)); } @@ -295,7 +308,7 @@ class SerializerSelectorTest { class A { List ls; } - var serializer = (ListSerializer) SELECTOR.select(getGenericType(A.class, "ls")); + var serializer = (ListSerializer) SELECTOR.select(comp(getGenericType(A.class, "ls"))); assertThat(serializer.getElementSerializer(), instanceOf(StringSerializer.class)); } @@ -304,7 +317,7 @@ class SerializerSelectorTest { class A { List> lls; } - var serializer = (ListSerializer) SELECTOR.select(getGenericType(A.class, "lls")); + var serializer = (ListSerializer) SELECTOR.select(comp(getGenericType(A.class, "lls"))); var elementSerializer = (ListSerializer) serializer.getElementSerializer(); assertThat(elementSerializer.getElementSerializer(), instanceOf(StringSerializer.class)); } @@ -317,7 +330,7 @@ class SerializerSelectorTest { SerializerSelector selector = new SerializerSelector( ConfigurationProperties.newBuilder().serializeSetsAsLists(false).build() ); - var serializer = (SetSerializer) selector.select(getGenericType(A.class, "ss")); + var serializer = (SetSerializer) selector.select(comp(getGenericType(A.class, "ss"))); assertThat(serializer.getElementSerializer(), instanceOf(StringSerializer.class)); } @@ -326,7 +339,7 @@ class SerializerSelectorTest { class A { Set ss; } - var serializer = (SetAsListSerializer) SELECTOR.select(getGenericType(A.class, "ss")); + var serializer = (SetAsListSerializer) SELECTOR.select(comp(getGenericType(A.class, "ss"))); assertThat(serializer.getElementSerializer(), instanceOf(StringSerializer.class)); } @@ -335,7 +348,7 @@ class SerializerSelectorTest { class A { Map mis; } - var serializer = (MapSerializer) SELECTOR.select(getGenericType(A.class, "mis")); + var serializer = (MapSerializer) SELECTOR.select(comp(getGenericType(A.class, "mis"))); var numberSerializer = (NumberSerializer) serializer.getKeySerializer(); assertThat(numberSerializer.getNumberClass(), equalTo(Integer.class)); assertThat(serializer.getValueSerializer(), instanceOf(StringSerializer.class)); @@ -347,7 +360,7 @@ class SerializerSelectorTest { class A { Map>> mesle; } - var serializer = (MapSerializer) SELECTOR.select(getGenericType(A.class, "mesle")); + var serializer = (MapSerializer) SELECTOR.select(comp(getGenericType(A.class, "mesle"))); var keySerializer = (EnumSerializer) serializer.getKeySerializer(); assertThat(keySerializer.getEnumCls(), equalTo(E.class)); @@ -365,7 +378,7 @@ class SerializerSelectorTest { } Type type = getGenericType(A.class, "mlss"); assertThrowsConfigurationException( - () -> SELECTOR.select(type), + () -> SELECTOR.select(comp(type)), "Cannot select serializer for type '" + type + "'.\nMap keys can only be " + "of simple or enum type." ); @@ -378,7 +391,7 @@ class SerializerSelectorTest { } Type type = getGenericType(A.class, "mps"); assertThrowsConfigurationException( - () -> SELECTOR.select(type), + () -> SELECTOR.select(comp(type)), "Cannot select serializer for type '" + type + "'.\nMap keys can only be " + "of simple or enum type." ); @@ -392,7 +405,7 @@ class SerializerSelectorTest { } Type type = getGenericType(A.class, "box"); assertThrowsConfigurationException( - () -> SELECTOR.select(type), + () -> SELECTOR.select(comp(type)), "Cannot select serializer for type '" + type + "'.\nParameterized " + "types other than lists, sets, and maps cannot be serialized." ); @@ -405,7 +418,7 @@ class SerializerSelectorTest { } Type type = getGenericType(A.class, "ga"); assertThrowsConfigurationException( - () -> SELECTOR.select(type), + () -> SELECTOR.select(comp(type)), "Cannot select serializer for type 'java.util.List[]'.\n" + "Generic array types cannot be serialized." ); @@ -419,7 +432,7 @@ class SerializerSelectorTest { ParameterizedType ptype = (ParameterizedType) getGenericType(A.class, "les"); Type type = ptype.getActualTypeArguments()[0]; assertThrowsConfigurationException( - () -> SELECTOR.select(type), + () -> SELECTOR.select(comp(type)), "Cannot select serializer for type '? extends java.lang.String'.\n" + "Wildcard types cannot be serialized." ); @@ -433,7 +446,7 @@ class SerializerSelectorTest { ParameterizedType ptype = (ParameterizedType) getGenericType(A.class, "lw"); Type type = ptype.getActualTypeArguments()[0]; assertThrowsConfigurationException( - () -> SELECTOR.select(type), + () -> SELECTOR.select(comp(type)), "Cannot select serializer for type '?'.\n" + "Wildcard types cannot be serialized." ); @@ -446,9 +459,143 @@ class SerializerSelectorTest { } Type type = getGenericType(A.class, "t"); assertThrowsConfigurationException( - () -> SELECTOR.select(type), + () -> SELECTOR.select(comp(type)), "Cannot select serializer for type 'T'.\n" + "Type variables cannot be serialized." ); } -} \ No newline at end of file + + static final class SerializeWithTests { + static class Z { + @SerializeWith(serializer = IdentitySerializer.class) + String string; + @SerializeWith(serializer = IdentitySerializer.class) + List> list1; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 1) + List> list2; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 2) + List> list3; + @SerializeWith(serializer = IdentitySerializer.class) + Set> set1; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 1) + Set> set2; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 2) + Set> set3; + @SerializeWith(serializer = IdentitySerializer.class) + Map> map1; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 1) + Map> map2; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 2) + Map> map3; + @SerializeWith(serializer = IdentitySerializer.class) + String[][] array1; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 1) + String[][] array2; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 2) + String[][] array3; + } + + @Test + void selectCustomSerializerForField() { + var serializer = SELECTOR.select(comp(Z.class, "string")); + assertThat(serializer, instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForListsWithNesting0() { + var serializer = SELECTOR.select(comp(Z.class, "list1")); + assertThat(serializer, instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForListsWithNesting1() { + var serializer = (ListSerializer) SELECTOR.select(comp(Z.class, "list2")); + assertThat(serializer.getElementSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForListsWithNesting2() { + var serializer1 = (ListSerializer) SELECTOR.select(comp(Z.class, "list3")); + var serializer2 = (SetAsListSerializer) serializer1.getElementSerializer(); + assertThat(serializer2.getElementSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForSetsWithNesting0() { + var serializer = SELECTOR.select(comp(Z.class, "set1")); + assertThat(serializer, instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForSetsWithNesting1() { + var serializer = (SetAsListSerializer) SELECTOR.select(comp(Z.class, "set2")); + assertThat(serializer.getElementSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForSetsWithNesting2() { + var serializer1 = (SetAsListSerializer) SELECTOR.select(comp(Z.class, "set3")); + var serializer2 = (ListSerializer) serializer1.getElementSerializer(); + assertThat(serializer2.getElementSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForMapsWithNesting0() { + var serializer = SELECTOR.select(comp(Z.class, "map1")); + assertThat(serializer, instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForMapsWithNesting1() { + var serializer = (MapSerializer) SELECTOR.select(comp(Z.class, "map2")); + assertThat(serializer.getKeySerializer(), instanceOf(NumberSerializer.class)); + assertThat(serializer.getValueSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForMapsWithNesting2() { + var serializer1 = (MapSerializer) SELECTOR.select(comp(Z.class, "map3")); + var serializer2 = (MapSerializer) serializer1.getValueSerializer(); + assertThat(serializer2.getKeySerializer(), instanceOf(StringSerializer.class)); + assertThat(serializer2.getValueSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForArraysWithNesting0() { + var serializer = SELECTOR.select(comp(Z.class, "array1")); + assertThat(serializer, instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForArraysWithNesting1() { + var serializer = (ArraySerializer) SELECTOR.select(comp(Z.class, "array2")); + assertThat(serializer.getElementSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerForArraysWithNesting2() { + var serializer1 = (ArraySerializer) SELECTOR.select(comp(Z.class, "array3")); + var serializer2 = (ArraySerializer) serializer1.getElementSerializer(); + assertThat(serializer2.getElementSerializer(), instanceOf(IdentitySerializer.class)); + } + + @Test + void selectCustomSerializerWithInvalidNestingNotSelected() { + class A { + @SerializeWith(serializer = IdentitySerializer.class, nesting = -1) + String s1; + @SerializeWith(serializer = IdentitySerializer.class) + String s2; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 1) + String s3; + @SerializeWith(serializer = IdentitySerializer.class, nesting = 2) + List list; + } + assertThat(SELECTOR.select(comp(A.class, "s1")), instanceOf(StringSerializer.class)); + assertThat(SELECTOR.select(comp(A.class, "s2")), instanceOf(IdentitySerializer.class)); + assertThat(SELECTOR.select(comp(A.class, "s3")), instanceOf(StringSerializer.class)); + var serializer = (ListSerializer) SELECTOR.select(comp(A.class, "list")); + assertThat(serializer.getElementSerializer(), instanceOf(StringSerializer.class)); + } + } +} diff --git a/configlib-core/src/testFixtures/java/de/exlll/configlib/TestUtils.java b/configlib-core/src/testFixtures/java/de/exlll/configlib/TestUtils.java index abad0c2..2d825f1 100644 --- a/configlib-core/src/testFixtures/java/de/exlll/configlib/TestUtils.java +++ b/configlib-core/src/testFixtures/java/de/exlll/configlib/TestUtils.java @@ -127,6 +127,19 @@ public final class TestUtils { } } + public static final class IdentitySerializer implements Serializer { + @Override + public Object serialize(Object element) { + return element; + } + + @Override + public Object deserialize(Object element) { + return element; + } + } + + @SafeVarargs public static Set asSet(E... elements) { return new LinkedHashSet<>(Arrays.asList(elements));