Change TypeComponent and SerializerSelector to use AnnotatedType

dev
Exlll 3 years ago
parent 1c38f85177
commit c78f4b2901

@ -71,18 +71,21 @@ final class SerializerSelector {
public Serializer<?, ?> select(TypeComponent<?> component) { public Serializer<?, ?> select(TypeComponent<?> component) {
this.currentNesting = -1; this.currentNesting = -1;
this.serializeWith = component.annotation(SerializeWith.class); this.serializeWith = component.annotation(SerializeWith.class);
return selectForType(component.genericType()); return selectForType(component.annotatedType());
} }
private Serializer<?, ?> selectForType(Type type) { private Serializer<?, ?> selectForType(AnnotatedType annotatedType) {
this.currentNesting++; this.currentNesting++;
final Serializer<?, ?> custom = selectCustomSerializer(type);
final Serializer<?, ?> custom = selectCustomSerializer(annotatedType);
if (custom != null) if (custom != null)
return custom; return custom;
if (type instanceof Class<?> cls) {
return selectForClass(cls); final Type type = annotatedType.getType();
} else if (type instanceof ParameterizedType pType) { if (type instanceof Class<?>) {
return selectForParameterizedType(pType); return selectForClass(annotatedType);
} else if (type instanceof ParameterizedType) {
return selectForParameterizedType((AnnotatedParameterizedType) annotatedType);
} else if (type instanceof WildcardType) { } else if (type instanceof WildcardType) {
String msg = baseExceptionMessage(type) + "Wildcard types cannot be serialized."; String msg = baseExceptionMessage(type) + "Wildcard types cannot be serialized.";
throw new ConfigurationException(msg); throw new ConfigurationException(msg);
@ -97,13 +100,19 @@ final class SerializerSelector {
throw new ConfigurationException(baseExceptionMessage(type)); throw new ConfigurationException(baseExceptionMessage(type));
} }
private Serializer<?, ?> selectCustomSerializer(Type type) { private Serializer<?, ?> selectCustomSerializer(AnnotatedType annotatedType) {
// SerializeWith annotation
if ((serializeWith != null) && (currentNesting == serializeWith.nesting())) if ((serializeWith != null) && (currentNesting == serializeWith.nesting()))
return Reflect.callNoParamConstructor(serializeWith.serializer()); return Reflect.callNoParamConstructor(serializeWith.serializer());
// Serializer registered for Type via configurations properties
final Type type = annotatedType.getType();
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);
} }
// Serializer registered for condition via configurations properties
for (var entry : properties.getSerializersByCondition().entrySet()) { for (var entry : properties.getSerializersByCondition().entrySet()) {
if (entry.getKey().test(type)) if (entry.getKey().test(type))
return entry.getValue(); return entry.getValue();
@ -111,7 +120,8 @@ final class SerializerSelector {
return null; return null;
} }
private Serializer<?, ?> selectForClass(Class<?> cls) { private Serializer<?, ?> selectForClass(AnnotatedType annotatedType) {
final Class<?> cls = (Class<?>) annotatedType.getType();
if (DEFAULT_SERIALIZERS.containsKey(cls)) if (DEFAULT_SERIALIZERS.containsKey(cls))
return DEFAULT_SERIALIZERS.get(cls); return DEFAULT_SERIALIZERS.get(cls);
if (Reflect.isEnumType(cls)) { if (Reflect.isEnumType(cls)) {
@ -120,8 +130,9 @@ final class SerializerSelector {
final var enumType = (Class<? extends Enum<?>>) cls; final var enumType = (Class<? extends Enum<?>>) cls;
return new Serializers.EnumSerializer(enumType); return new Serializers.EnumSerializer(enumType);
} }
if (Reflect.isArrayType(cls)) if (Reflect.isArrayType(cls)) {
return selectForArray(cls.getComponentType()); return selectForArray((AnnotatedArrayType) annotatedType);
}
if (cls.isRecord()) { if (cls.isRecord()) {
// The following cast won't fail because we just checked that it's a record. // The following cast won't fail because we just checked that it's a record.
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -137,7 +148,9 @@ final class SerializerSelector {
throw new ConfigurationException(msg); throw new ConfigurationException(msg);
} }
private Serializer<?, ?> selectForArray(Class<?> elementType) { private Serializer<?, ?> selectForArray(AnnotatedArrayType annotatedType) {
final AnnotatedType annotatedElementType = annotatedType.getAnnotatedGenericComponentType();
final Class<?> elementType = (Class<?>) annotatedElementType.getType();
if (elementType == boolean.class) { if (elementType == boolean.class) {
return new PrimitiveBooleanArraySerializer(); return new PrimitiveBooleanArraySerializer();
} else if (elementType == char.class) { } else if (elementType == char.class) {
@ -155,16 +168,17 @@ final class SerializerSelector {
} else if (elementType == double.class) { } else if (elementType == double.class) {
return new PrimitiveDoubleArraySerializer(); return new PrimitiveDoubleArraySerializer();
} }
var elementSerializer = selectForType(elementType); var elementSerializer = selectForType(annotatedElementType);
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);
} }
private Serializer<?, ?> selectForParameterizedType(ParameterizedType type) { private Serializer<?, ?> selectForParameterizedType(AnnotatedParameterizedType annotatedType) {
// the raw type returned by Java is always a class // the raw type returned by Java is always a class
final var type = (ParameterizedType) annotatedType.getType();
final var rawType = (Class<?>) type.getRawType(); final var rawType = (Class<?>) type.getRawType();
final var typeArgs = type.getActualTypeArguments(); final var typeArgs = annotatedType.getAnnotatedActualTypeArguments();
final var inputNulls = properties.inputNulls(); final var inputNulls = properties.inputNulls();
final var outputNulls = properties.outputNulls(); final var outputNulls = properties.outputNulls();
@ -177,10 +191,10 @@ final class SerializerSelector {
? new SetAsListSerializer<>(elementSerializer, outputNulls, inputNulls) ? new SetAsListSerializer<>(elementSerializer, outputNulls, inputNulls)
: new SetSerializer<>(elementSerializer, outputNulls, inputNulls); : new SetSerializer<>(elementSerializer, outputNulls, inputNulls);
} else if (Reflect.isMapType(rawType)) { } else if (Reflect.isMapType(rawType)) {
if ((typeArgs[0] instanceof Class<?> cls) && if ((typeArgs[0].getType() instanceof Class<?> cls) &&
(DEFAULT_SERIALIZERS.containsKey(cls) || (DEFAULT_SERIALIZERS.containsKey(cls) ||
Reflect.isEnumType(cls))) { Reflect.isEnumType(cls))) {
var keySerializer = selectForClass(cls); var keySerializer = selectForClass(typeArgs[0]);
var valSerializer = selectForType(typeArgs[1]); var valSerializer = selectForType(typeArgs[1]);
return new MapSerializer<>(keySerializer, valSerializer, outputNulls, inputNulls); return new MapSerializer<>(keySerializer, valSerializer, outputNulls, inputNulls);
} }
@ -195,6 +209,6 @@ final class SerializerSelector {
} }
private String baseExceptionMessage(Type type) { private String baseExceptionMessage(Type type) {
return "Cannot select serializer for type '" + type + "'.\n"; return "Cannot select serializer for type '%s'.\n".formatted(type);
} }
} }

@ -1,10 +1,7 @@
package de.exlll.configlib; package de.exlll.configlib;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.*;
import java.lang.reflect.Field;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type;
import static de.exlll.configlib.Validator.requireNonNull; import static de.exlll.configlib.Validator.requireNonNull;
@ -37,11 +34,11 @@ sealed interface TypeComponent<T extends AnnotatedElement> {
Class<?> type(); Class<?> type();
/** /**
* Returns the generic type of the component. * Returns the annotated type of the component.
* *
* @return generic type of the component * @return annotated type of component
*/ */
Type genericType(); AnnotatedType annotatedType();
/** /**
* Returns the value the component is holding. * Returns the value the component is holding.
@ -89,8 +86,8 @@ sealed interface TypeComponent<T extends AnnotatedElement> {
} }
@Override @Override
public Type genericType() { public AnnotatedType annotatedType() {
return component.getGenericType(); return component.getAnnotatedType();
} }
@Override @Override
@ -116,13 +113,13 @@ sealed interface TypeComponent<T extends AnnotatedElement> {
} }
@Override @Override
public Class<?> type() { public AnnotatedType annotatedType() {
return component.getType(); return component.getAnnotatedType();
} }
@Override @Override
public Type genericType() { public Class<?> type() {
return component.getGenericType(); return component.getType();
} }
@Override @Override

@ -370,7 +370,7 @@ class SerializerSelectorTest {
() -> SELECTOR.select(component), () -> SELECTOR.select(component),
("Cannot select serializer for type '%s'.\n" + ("Cannot select serializer for type '%s'.\n" +
"Map keys can only be of simple or enum type.") "Map keys can only be of simple or enum type.")
.formatted(component.genericType()) .formatted(component.annotatedType().getType())
); );
} }
@ -384,7 +384,7 @@ class SerializerSelectorTest {
() -> SELECTOR.select(component), () -> SELECTOR.select(component),
("Cannot select serializer for type '%s'.\n" + ("Cannot select serializer for type '%s'.\n" +
"Map keys can only be of simple or enum type.") "Map keys can only be of simple or enum type.")
.formatted(component.genericType()) .formatted(component.annotatedType().getType())
); );
} }
@ -399,7 +399,7 @@ class SerializerSelectorTest {
() -> SELECTOR.select(component), () -> SELECTOR.select(component),
("Cannot select serializer for type '%s'.\n" + ("Cannot select serializer for type '%s'.\n" +
"Parameterized types other than lists, sets, and maps cannot be serialized.") "Parameterized types other than lists, sets, and maps cannot be serialized.")
.formatted(component.genericType()) .formatted(component.annotatedType().getType())
); );
} }

@ -5,9 +5,7 @@ import de.exlll.configlib.TypeComponent.ConfigurationRecordComponent;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.RecordComponent; import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -36,10 +34,8 @@ class TypeComponentTest {
} }
@Test @Test
void componentGenericType() { void componentAnnotatedType() {
ParameterizedType type = (ParameterizedType) COMPONENT.genericType(); assertThat(COMPONENT.annotatedType(), equalTo(FIELD.getAnnotatedType()));
Type argument = type.getActualTypeArguments()[0];
assertThat(argument, equalTo(String.class));
} }
@Test @Test
@ -76,10 +72,8 @@ class TypeComponentTest {
} }
@Test @Test
void componentGenericType() { void componentAnnotatedType() {
ParameterizedType type = (ParameterizedType) COMPONENT.genericType(); assertThat(COMPONENT.annotatedType(), equalTo(RECORD_COMPONENT.getAnnotatedType()));
Type argument = type.getActualTypeArguments()[0];
assertThat(argument, equalTo(Integer.class));
} }
@Test @Test

Loading…
Cancel
Save