Add support for SerializeWith annotation

dev
Exlll 3 years ago
parent 0a291fe922
commit 96321dd682

@ -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.
* <p>
* 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.
* <p>
* The following example shows how {@code nesting} can be used to apply the serializer at
* different levels.
*
* <pre>
* {@code
* // MyListSerializer is applied to 'list'
* @SerializeWith(serializer = MyListSerializer.class)
* List<Set<String>> list;
*
* // MySetSerializer is applied to the Set<String> elements of 'list'
* @SerializeWith(serializer = MySetSerializer.class, nesting = 1)
* List<Set<String>> list;
*
* // MyStringSerializer is applied to the strings within the set elements of 'list'
* @SerializeWith(serializer = MyStringSerializer.class, nesting = 2)
* List<Set<String>> list;
*
* // MyMap0Serializer is applied to 'map'
* @SerializeWith(serializer = MyMap0Serializer.class)
* Map<Integer, Map<String, Double>> map;
*
* // MyMap1Serializer is applied to the Map<String, Double> values of 'map'
* @SerializeWith(serializer = MyMap1Serializer.class, nesting = 1)
* Map<Integer, Map<String, Double>> map;
*
* // MyDoubleSerializer is applied to the doubles within the nested values of 'map'
* @SerializeWith(serializer = MyDoubleSerializer.class, nesting = 2)
* Map<Integer, Map<String, Double>> map;
* }
* </pre>
*/
@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<? extends Serializer<?, ?>> serializer();
/**
* Returns the nesting level at which to apply the serializer.
*
* @return the nesting level
*/
int nesting() default 0;
}

@ -50,12 +50,32 @@ final class SerializerSelector {
Map.entry(URI.class, new UriSerializer()) Map.entry(URI.class, new UriSerializer())
); );
private final ConfigurationProperties properties; 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.
* <p>
* For example, for a field {@code List<Set<String>>}, 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) { public SerializerSelector(ConfigurationProperties properties) {
this.properties = requireNonNull(properties, "configuration 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); final Serializer<?, ?> custom = selectCustomSerializer(type);
if (custom != null) if (custom != null)
return custom; return custom;
@ -78,6 +98,8 @@ final class SerializerSelector {
} }
private Serializer<?, ?> selectCustomSerializer(Type type) { private Serializer<?, ?> selectCustomSerializer(Type type) {
if ((serializeWith != null) && (currentNesting == serializeWith.nesting()))
return Reflect.callNoParamConstructor(serializeWith.serializer());
if (type instanceof Class<?> cls) { if (type instanceof Class<?> cls) {
if (properties.getSerializers().containsKey(cls)) if (properties.getSerializers().containsKey(cls))
return properties.getSerializers().get(cls); return properties.getSerializers().get(cls);
@ -133,7 +155,7 @@ final class SerializerSelector {
} else if (elementType == double.class) { } else if (elementType == double.class) {
return new PrimitiveDoubleArraySerializer(); return new PrimitiveDoubleArraySerializer();
} }
var elementSerializer = select(elementType); var elementSerializer = selectForType(elementType);
var inputNulls = properties.inputNulls(); var inputNulls = properties.inputNulls();
var outputNulls = properties.outputNulls(); var outputNulls = properties.outputNulls();
return new ArraySerializer<>(elementType, elementSerializer, outputNulls, inputNulls); return new ArraySerializer<>(elementType, elementSerializer, outputNulls, inputNulls);
@ -147,10 +169,10 @@ final class SerializerSelector {
final var outputNulls = properties.outputNulls(); final var outputNulls = properties.outputNulls();
if (Reflect.isListType(rawType)) { if (Reflect.isListType(rawType)) {
var elementSerializer = select(typeArgs[0]); var elementSerializer = selectForType(typeArgs[0]);
return new ListSerializer<>(elementSerializer, outputNulls, inputNulls); return new ListSerializer<>(elementSerializer, outputNulls, inputNulls);
} else if (Reflect.isSetType(rawType)) { } else if (Reflect.isSetType(rawType)) {
var elementSerializer = select(typeArgs[0]); var elementSerializer = selectForType(typeArgs[0]);
return properties.serializeSetsAsLists() return properties.serializeSetsAsLists()
? new SetAsListSerializer<>(elementSerializer, outputNulls, inputNulls) ? new SetAsListSerializer<>(elementSerializer, outputNulls, inputNulls)
: new SetSerializer<>(elementSerializer, outputNulls, inputNulls); : new SetSerializer<>(elementSerializer, outputNulls, inputNulls);
@ -158,8 +180,8 @@ final class SerializerSelector {
if ((typeArgs[0] instanceof Class<?> cls) && if ((typeArgs[0] instanceof Class<?> cls) &&
(DEFAULT_SERIALIZERS.containsKey(cls) || (DEFAULT_SERIALIZERS.containsKey(cls) ||
Reflect.isEnumType(cls))) { Reflect.isEnumType(cls))) {
var keySerializer = select(typeArgs[0]); var keySerializer = selectForClass(cls);
var valSerializer = select(typeArgs[1]); var valSerializer = selectForType(typeArgs[1]);
return new MapSerializer<>(keySerializer, valSerializer, outputNulls, inputNulls); return new MapSerializer<>(keySerializer, valSerializer, outputNulls, inputNulls);
} }
String msg = baseExceptionMessage(type) + String msg = baseExceptionMessage(type) +

@ -14,7 +14,7 @@ import static de.exlll.configlib.Validator.requireNonNull;
* *
* @param <T> the type of the component * @param <T> the type of the component
*/ */
sealed interface TypeComponent<T extends AnnotatedElement> { interface TypeComponent<T extends AnnotatedElement> {
/** /**
* Returns the component itself. * Returns the component itself.
* *

@ -37,7 +37,7 @@ sealed abstract class TypeSerializer<T, TC extends TypeComponent<?>>
try { try {
return components().stream().collect(Collectors.toMap( return components().stream().collect(Collectors.toMap(
TypeComponent::name, TypeComponent::name,
component -> selector.select(component.genericType()) selector::select
)); ));
} catch (StackOverflowError error) { } catch (StackOverflowError error) {
String msg = "Recursive type definitions are not supported."; String msg = "Recursive type definitions are not supported.";

@ -4,6 +4,7 @@ import de.exlll.configlib.Serializers.*;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;
import java.awt.Point; import java.awt.Point;
import java.io.File; import java.io.File;
@ -28,6 +29,7 @@ import static de.exlll.configlib.TestUtils.*;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
@SuppressWarnings("unused")
class SerializerSelectorTest { class SerializerSelectorTest {
private static final SerializerSelector SELECTOR = new SerializerSelector( private static final SerializerSelector SELECTOR = new SerializerSelector(
ConfigurationProperties.newBuilder().build() ConfigurationProperties.newBuilder().build()
@ -38,10 +40,21 @@ class SerializerSelectorTest {
return ls.getGenericType(); 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 @ParameterizedTest
@ValueSource(classes = {boolean.class, Boolean.class}) @ValueSource(classes = {boolean.class, Boolean.class})
void selectSerializerBoolean(Class<?> cls) { void selectSerializerBoolean(Class<?> cls) {
Serializer<?, ?> serializer = SELECTOR.select(cls); Serializer<?, ?> serializer = SELECTOR.select(comp(cls));
assertThat(serializer, instanceOf(BooleanSerializer.class)); assertThat(serializer, instanceOf(BooleanSerializer.class));
} }
@ -52,99 +65,99 @@ class SerializerSelectorTest {
float.class, Float.class, double.class, Double.class float.class, Float.class, double.class, Double.class
}) })
void selectSerializerNumber(Class<?> cls) { void selectSerializerNumber(Class<?> cls) {
NumberSerializer serializer = (NumberSerializer) SELECTOR.select(cls); NumberSerializer serializer = (NumberSerializer) SELECTOR.select(comp(cls));
assertThat(serializer.getNumberClass(), equalTo(cls)); assertThat(serializer.getNumberClass(), equalTo(cls));
} }
@ParameterizedTest @ParameterizedTest
@ValueSource(classes = {char.class, Character.class}) @ValueSource(classes = {char.class, Character.class})
void selectSerializerChar(Class<?> cls) { void selectSerializerChar(Class<?> cls) {
Serializer<?, ?> serializer = SELECTOR.select(cls); Serializer<?, ?> serializer = SELECTOR.select(comp(cls));
assertThat(serializer, instanceOf(CharacterSerializer.class)); assertThat(serializer, instanceOf(CharacterSerializer.class));
} }
@Test @Test
void selectSerializerString() { void selectSerializerString() {
Serializer<?, ?> serializer = SELECTOR.select(String.class); Serializer<?, ?> serializer = SELECTOR.select(comp(String.class));
assertThat(serializer, instanceOf(StringSerializer.class)); assertThat(serializer, instanceOf(StringSerializer.class));
} }
@Test @Test
void selectSerializerBigInteger() { void selectSerializerBigInteger() {
Serializer<?, ?> serializer = SELECTOR.select(BigInteger.class); Serializer<?, ?> serializer = SELECTOR.select(comp(BigInteger.class));
assertThat(serializer, instanceOf(BigIntegerSerializer.class)); assertThat(serializer, instanceOf(BigIntegerSerializer.class));
} }
@Test @Test
void selectSerializerBigDecimal() { void selectSerializerBigDecimal() {
Serializer<?, ?> serializer = SELECTOR.select(BigDecimal.class); Serializer<?, ?> serializer = SELECTOR.select(comp(BigDecimal.class));
assertThat(serializer, instanceOf(BigDecimalSerializer.class)); assertThat(serializer, instanceOf(BigDecimalSerializer.class));
} }
@Test @Test
void selectSerializerLocalDate() { void selectSerializerLocalDate() {
Serializer<?, ?> serializer = SELECTOR.select(LocalDate.class); Serializer<?, ?> serializer = SELECTOR.select(comp(LocalDate.class));
assertThat(serializer, instanceOf(LocalDateSerializer.class)); assertThat(serializer, instanceOf(LocalDateSerializer.class));
} }
@Test @Test
void selectSerializerLocalTime() { void selectSerializerLocalTime() {
Serializer<?, ?> serializer = SELECTOR.select(LocalTime.class); Serializer<?, ?> serializer = SELECTOR.select(comp(LocalTime.class));
assertThat(serializer, instanceOf(LocalTimeSerializer.class)); assertThat(serializer, instanceOf(LocalTimeSerializer.class));
} }
@Test @Test
void selectSerializerLocalDateTime() { void selectSerializerLocalDateTime() {
Serializer<?, ?> serializer = SELECTOR.select(LocalDateTime.class); Serializer<?, ?> serializer = SELECTOR.select(comp(LocalDateTime.class));
assertThat(serializer, instanceOf(LocalDateTimeSerializer.class)); assertThat(serializer, instanceOf(LocalDateTimeSerializer.class));
} }
@Test @Test
void selectSerializerInstant() { void selectSerializerInstant() {
Serializer<?, ?> serializer = SELECTOR.select(Instant.class); Serializer<?, ?> serializer = SELECTOR.select(comp(Instant.class));
assertThat(serializer, instanceOf(InstantSerializer.class)); assertThat(serializer, instanceOf(InstantSerializer.class));
} }
@Test @Test
void selectSerializerUuid() { void selectSerializerUuid() {
Serializer<?, ?> serializer = SELECTOR.select(UUID.class); Serializer<?, ?> serializer = SELECTOR.select(comp(UUID.class));
assertThat(serializer, instanceOf(UuidSerializer.class)); assertThat(serializer, instanceOf(UuidSerializer.class));
} }
@Test @Test
void selectSerializerFile() { void selectSerializerFile() {
Serializer<?, ?> serializer = SELECTOR.select(File.class); Serializer<?, ?> serializer = SELECTOR.select(comp(File.class));
assertThat(serializer, instanceOf(FileSerializer.class)); assertThat(serializer, instanceOf(FileSerializer.class));
} }
@Test @Test
void selectSerializerPath() { void selectSerializerPath() {
Serializer<?, ?> serializer = SELECTOR.select(Path.class); Serializer<?, ?> serializer = SELECTOR.select(comp(Path.class));
assertThat(serializer, instanceOf(PathSerializer.class)); assertThat(serializer, instanceOf(PathSerializer.class));
} }
@Test @Test
void selectSerializerUrl() { void selectSerializerUrl() {
Serializer<?, ?> serializer = SELECTOR.select(URL.class); Serializer<?, ?> serializer = SELECTOR.select(comp(URL.class));
assertThat(serializer, instanceOf(UrlSerializer.class)); assertThat(serializer, instanceOf(UrlSerializer.class));
} }
@Test @Test
void selectSerializerUri() { void selectSerializerUri() {
Serializer<?, ?> serializer = SELECTOR.select(URI.class); Serializer<?, ?> serializer = SELECTOR.select(comp(URI.class));
assertThat(serializer, instanceOf(UriSerializer.class)); assertThat(serializer, instanceOf(UriSerializer.class));
} }
@Test @Test
void selectSerializerEnum() { void selectSerializerEnum() {
enum E {} enum E {}
EnumSerializer serializer = (EnumSerializer) SELECTOR.select(E.class); EnumSerializer serializer = (EnumSerializer) SELECTOR.select(comp(E.class));
assertThat(serializer.getEnumCls(), equalTo(E.class)); assertThat(serializer.getEnumCls(), equalTo(E.class));
} }
@Test @Test
void selectSerializerArray() { void selectSerializerArray() {
var serializer = (ArraySerializer<?, ?>) SELECTOR.select(String[][].class); var serializer = (ArraySerializer<?, ?>) SELECTOR.select(comp(String[][].class));
assertThat(serializer.getComponentType(), equalTo(String[].class)); assertThat(serializer.getComponentType(), equalTo(String[].class));
var elementSerializer = (ArraySerializer<?, ?>) serializer.getElementSerializer(); var elementSerializer = (ArraySerializer<?, ?>) serializer.getElementSerializer();
@ -154,49 +167,49 @@ class SerializerSelectorTest {
@Test @Test
void selectSerializerPrimitiveBooleanArray() { void selectSerializerPrimitiveBooleanArray() {
Serializer<?, ?> serializer = SELECTOR.select(boolean[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(boolean[].class));
assertThat(serializer, instanceOf(PrimitiveBooleanArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveBooleanArraySerializer.class));
} }
@Test @Test
void selectSerializerPrimitiveCharacterArray() { void selectSerializerPrimitiveCharacterArray() {
Serializer<?, ?> serializer = SELECTOR.select(char[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(char[].class));
assertThat(serializer, instanceOf(PrimitiveCharacterArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveCharacterArraySerializer.class));
} }
@Test @Test
void selectSerializerPrimitiveByteArray() { void selectSerializerPrimitiveByteArray() {
Serializer<?, ?> serializer = SELECTOR.select(byte[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(byte[].class));
assertThat(serializer, instanceOf(PrimitiveByteArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveByteArraySerializer.class));
} }
@Test @Test
void selectSerializerPrimitiveShortArray() { void selectSerializerPrimitiveShortArray() {
Serializer<?, ?> serializer = SELECTOR.select(short[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(short[].class));
assertThat(serializer, instanceOf(PrimitiveShortArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveShortArraySerializer.class));
} }
@Test @Test
void selectSerializerPrimitiveIntegerArray() { void selectSerializerPrimitiveIntegerArray() {
Serializer<?, ?> serializer = SELECTOR.select(int[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(int[].class));
assertThat(serializer, instanceOf(PrimitiveIntegerArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveIntegerArraySerializer.class));
} }
@Test @Test
void selectSerializerPrimitiveLongArray() { void selectSerializerPrimitiveLongArray() {
Serializer<?, ?> serializer = SELECTOR.select(long[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(long[].class));
assertThat(serializer, instanceOf(PrimitiveLongArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveLongArraySerializer.class));
} }
@Test @Test
void selectSerializerPrimitiveFloatArray() { void selectSerializerPrimitiveFloatArray() {
Serializer<?, ?> serializer = SELECTOR.select(float[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(float[].class));
assertThat(serializer, instanceOf(PrimitiveFloatArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveFloatArraySerializer.class));
} }
@Test @Test
void selectSerializerPrimitiveDoubleArray() { void selectSerializerPrimitiveDoubleArray() {
Serializer<?, ?> serializer = SELECTOR.select(double[].class); Serializer<?, ?> serializer = SELECTOR.select(comp(double[].class));
assertThat(serializer, instanceOf(PrimitiveDoubleArraySerializer.class)); assertThat(serializer, instanceOf(PrimitiveDoubleArraySerializer.class));
} }
@ -206,14 +219,14 @@ class SerializerSelectorTest {
class A<T> { class A<T> {
int i; int i;
} }
var serializer = (ConfigurationSerializer<?>) SELECTOR.select(A.class); var serializer = (ConfigurationSerializer<?>) SELECTOR.select(comp(A.class));
assertThat(serializer.getConfigurationType(), equalTo(A.class)); assertThat(serializer.getConfigurationType(), equalTo(A.class));
} }
@Test @Test
void selectSerializerRecord() { void selectSerializerRecord() {
record R(int i) {} 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)); assertThat(serializer.getRecordType(), equalTo(R.class));
} }
@ -221,14 +234,14 @@ class SerializerSelectorTest {
void recordSerializerTakesPrecedenceOverConfigurationSerializer() { void recordSerializerTakesPrecedenceOverConfigurationSerializer() {
@Configuration @Configuration
record R(int i) {} 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)); assertThat(serializer.getRecordType(), equalTo(R.class));
} }
@Test @Test
void selectSerializerMissingType() { void selectSerializerMissingType() {
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(Object.class), () -> SELECTOR.select(comp(Object.class)),
"Missing serializer for type class java.lang.Object.\nEither annotate the type with " + "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." "@Configuration or provide a custom serializer by adding it to the properties."
); );
@ -240,7 +253,7 @@ class SerializerSelectorTest {
.addSerializer(Point.class, POINT_SERIALIZER) .addSerializer(Point.class, POINT_SERIALIZER)
.build(); .build();
SerializerSelector selector = new SerializerSelector(properties); SerializerSelector selector = new SerializerSelector(properties);
var pointSerializer = selector.select(Point.class); var pointSerializer = selector.select(comp(Point.class));
assertThat(pointSerializer, sameInstance(POINT_SERIALIZER)); assertThat(pointSerializer, sameInstance(POINT_SERIALIZER));
} }
@ -250,7 +263,7 @@ class SerializerSelectorTest {
.addSerializer(BigInteger.class, CUSTOM_BIG_INTEGER_SERIALIZER) .addSerializer(BigInteger.class, CUSTOM_BIG_INTEGER_SERIALIZER)
.build(); .build();
SerializerSelector selector = new SerializerSelector(properties); 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, instanceOf(TestUtils.CustomBigIntegerSerializer.class));
assertThat(bigIntegerSerializer, sameInstance(CUSTOM_BIG_INTEGER_SERIALIZER)); assertThat(bigIntegerSerializer, sameInstance(CUSTOM_BIG_INTEGER_SERIALIZER));
} }
@ -261,7 +274,7 @@ class SerializerSelectorTest {
.addSerializerByCondition(t -> t == Point.class, POINT_SERIALIZER) .addSerializerByCondition(t -> t == Point.class, POINT_SERIALIZER)
.build(); .build();
SerializerSelector selector = new SerializerSelector(properties); SerializerSelector selector = new SerializerSelector(properties);
var pointSerializer = selector.select(Point.class); var pointSerializer = selector.select(comp(Point.class));
assertThat(pointSerializer, sameInstance(POINT_SERIALIZER)); assertThat(pointSerializer, sameInstance(POINT_SERIALIZER));
} }
@ -271,7 +284,7 @@ class SerializerSelectorTest {
.addSerializerByCondition(t -> t == BigInteger.class, CUSTOM_BIG_INTEGER_SERIALIZER) .addSerializerByCondition(t -> t == BigInteger.class, CUSTOM_BIG_INTEGER_SERIALIZER)
.build(); .build();
SerializerSelector selector = new SerializerSelector(properties); 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, instanceOf(TestUtils.CustomBigIntegerSerializer.class));
assertThat(bigIntegerSerializer, sameInstance(CUSTOM_BIG_INTEGER_SERIALIZER)); assertThat(bigIntegerSerializer, sameInstance(CUSTOM_BIG_INTEGER_SERIALIZER));
} }
@ -285,7 +298,7 @@ class SerializerSelectorTest {
.addSerializer(int.class, serializer2) .addSerializer(int.class, serializer2)
.build(); .build();
SerializerSelector selector = new SerializerSelector(properties); 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, instanceOf(IdentifiableSerializer.class));
assertThat(serializer, sameInstance(serializer2)); assertThat(serializer, sameInstance(serializer2));
} }
@ -295,7 +308,7 @@ class SerializerSelectorTest {
class A { class A {
List<String> ls; List<String> 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)); assertThat(serializer.getElementSerializer(), instanceOf(StringSerializer.class));
} }
@ -304,7 +317,7 @@ class SerializerSelectorTest {
class A { class A {
List<List<String>> lls; List<List<String>> 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(); var elementSerializer = (ListSerializer<?, ?>) serializer.getElementSerializer();
assertThat(elementSerializer.getElementSerializer(), instanceOf(StringSerializer.class)); assertThat(elementSerializer.getElementSerializer(), instanceOf(StringSerializer.class));
} }
@ -317,7 +330,7 @@ class SerializerSelectorTest {
SerializerSelector selector = new SerializerSelector( SerializerSelector selector = new SerializerSelector(
ConfigurationProperties.newBuilder().serializeSetsAsLists(false).build() 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)); assertThat(serializer.getElementSerializer(), instanceOf(StringSerializer.class));
} }
@ -326,7 +339,7 @@ class SerializerSelectorTest {
class A { class A {
Set<String> ss; Set<String> 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)); assertThat(serializer.getElementSerializer(), instanceOf(StringSerializer.class));
} }
@ -335,7 +348,7 @@ class SerializerSelectorTest {
class A { class A {
Map<Integer, String> mis; Map<Integer, String> 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(); var numberSerializer = (NumberSerializer) serializer.getKeySerializer();
assertThat(numberSerializer.getNumberClass(), equalTo(Integer.class)); assertThat(numberSerializer.getNumberClass(), equalTo(Integer.class));
assertThat(serializer.getValueSerializer(), instanceOf(StringSerializer.class)); assertThat(serializer.getValueSerializer(), instanceOf(StringSerializer.class));
@ -347,7 +360,7 @@ class SerializerSelectorTest {
class A { class A {
Map<E, Set<List<E>>> mesle; Map<E, Set<List<E>>> 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(); var keySerializer = (EnumSerializer) serializer.getKeySerializer();
assertThat(keySerializer.getEnumCls(), equalTo(E.class)); assertThat(keySerializer.getEnumCls(), equalTo(E.class));
@ -365,7 +378,7 @@ class SerializerSelectorTest {
} }
Type type = getGenericType(A.class, "mlss"); Type type = getGenericType(A.class, "mlss");
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(type), () -> SELECTOR.select(comp(type)),
"Cannot select serializer for type '" + type + "'.\nMap keys can only be " + "Cannot select serializer for type '" + type + "'.\nMap keys can only be " +
"of simple or enum type." "of simple or enum type."
); );
@ -378,7 +391,7 @@ class SerializerSelectorTest {
} }
Type type = getGenericType(A.class, "mps"); Type type = getGenericType(A.class, "mps");
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(type), () -> SELECTOR.select(comp(type)),
"Cannot select serializer for type '" + type + "'.\nMap keys can only be " + "Cannot select serializer for type '" + type + "'.\nMap keys can only be " +
"of simple or enum type." "of simple or enum type."
); );
@ -392,7 +405,7 @@ class SerializerSelectorTest {
} }
Type type = getGenericType(A.class, "box"); Type type = getGenericType(A.class, "box");
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(type), () -> SELECTOR.select(comp(type)),
"Cannot select serializer for type '" + type + "'.\nParameterized " + "Cannot select serializer for type '" + type + "'.\nParameterized " +
"types other than lists, sets, and maps cannot be serialized." "types other than lists, sets, and maps cannot be serialized."
); );
@ -405,7 +418,7 @@ class SerializerSelectorTest {
} }
Type type = getGenericType(A.class, "ga"); Type type = getGenericType(A.class, "ga");
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(type), () -> SELECTOR.select(comp(type)),
"Cannot select serializer for type 'java.util.List<?>[]'.\n" + "Cannot select serializer for type 'java.util.List<?>[]'.\n" +
"Generic array types cannot be serialized." "Generic array types cannot be serialized."
); );
@ -419,7 +432,7 @@ class SerializerSelectorTest {
ParameterizedType ptype = (ParameterizedType) getGenericType(A.class, "les"); ParameterizedType ptype = (ParameterizedType) getGenericType(A.class, "les");
Type type = ptype.getActualTypeArguments()[0]; Type type = ptype.getActualTypeArguments()[0];
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(type), () -> SELECTOR.select(comp(type)),
"Cannot select serializer for type '? extends java.lang.String'.\n" + "Cannot select serializer for type '? extends java.lang.String'.\n" +
"Wildcard types cannot be serialized." "Wildcard types cannot be serialized."
); );
@ -433,7 +446,7 @@ class SerializerSelectorTest {
ParameterizedType ptype = (ParameterizedType) getGenericType(A.class, "lw"); ParameterizedType ptype = (ParameterizedType) getGenericType(A.class, "lw");
Type type = ptype.getActualTypeArguments()[0]; Type type = ptype.getActualTypeArguments()[0];
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(type), () -> SELECTOR.select(comp(type)),
"Cannot select serializer for type '?'.\n" + "Cannot select serializer for type '?'.\n" +
"Wildcard types cannot be serialized." "Wildcard types cannot be serialized."
); );
@ -446,9 +459,143 @@ class SerializerSelectorTest {
} }
Type type = getGenericType(A.class, "t"); Type type = getGenericType(A.class, "t");
assertThrowsConfigurationException( assertThrowsConfigurationException(
() -> SELECTOR.select(type), () -> SELECTOR.select(comp(type)),
"Cannot select serializer for type 'T'.\n" + "Cannot select serializer for type 'T'.\n" +
"Type variables cannot be serialized." "Type variables cannot be serialized."
); );
} }
}
static final class SerializeWithTests {
static class Z {
@SerializeWith(serializer = IdentitySerializer.class)
String string;
@SerializeWith(serializer = IdentitySerializer.class)
List<Set<String>> list1;
@SerializeWith(serializer = IdentitySerializer.class, nesting = 1)
List<Set<String>> list2;
@SerializeWith(serializer = IdentitySerializer.class, nesting = 2)
List<Set<String>> list3;
@SerializeWith(serializer = IdentitySerializer.class)
Set<List<String>> set1;
@SerializeWith(serializer = IdentitySerializer.class, nesting = 1)
Set<List<String>> set2;
@SerializeWith(serializer = IdentitySerializer.class, nesting = 2)
Set<List<String>> set3;
@SerializeWith(serializer = IdentitySerializer.class)
Map<Integer, Map<String, Double>> map1;
@SerializeWith(serializer = IdentitySerializer.class, nesting = 1)
Map<Integer, Map<String, Double>> map2;
@SerializeWith(serializer = IdentitySerializer.class, nesting = 2)
Map<Integer, Map<String, Double>> 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<String> 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));
}
}
}

@ -127,6 +127,19 @@ public final class TestUtils {
} }
} }
public static final class IdentitySerializer implements Serializer<Object, Object> {
@Override
public Object serialize(Object element) {
return element;
}
@Override
public Object deserialize(Object element) {
return element;
}
}
@SafeVarargs @SafeVarargs
public static <E> Set<E> asSet(E... elements) { public static <E> Set<E> asSet(E... elements) {
return new LinkedHashSet<>(Arrays.asList(elements)); return new LinkedHashSet<>(Arrays.asList(elements));

Loading…
Cancel
Save