@ -1,8 +1,10 @@
package de.exlll.configlib ;
package de.exlll.configlib ;
import de.exlll.configlib.Serializers.* ;
import de.exlll.configlib.Serializers.* ;
import de.exlll.configlib.util.MapUtil ;
import java.io.File ;
import java.io.File ;
import java.lang.annotation.Annotation ;
import java.lang.reflect.* ;
import java.lang.reflect.* ;
import java.math.BigDecimal ;
import java.math.BigDecimal ;
import java.math.BigInteger ;
import java.math.BigInteger ;
@ -16,39 +18,41 @@ import java.time.LocalTime;
import java.util.Map ;
import java.util.Map ;
import java.util.Optional ;
import java.util.Optional ;
import java.util.UUID ;
import java.util.UUID ;
import java.util.function.Function ;
import java.util.function.Predicate ;
import static de.exlll.configlib.Validator.requireNonNull ;
import static de.exlll.configlib.Validator.requireNonNull ;
final class SerializerSelector {
final class SerializerSelector {
private static final Map < Class < ? > , Serializer < ? , ? > > DEFAULT_SERIALIZERS = Map . ofEntries (
private static final Map < Class < ? > , Serializer < ? , ? > > DEFAULT_SERIALIZERS = Map . ofEntries (
Map . entry ( boolean . class , new BooleanSerializer ( ) ) ,
Map Util . entry ( boolean . class , new BooleanSerializer ( ) ) ,
Map . entry ( Boolean . class , new BooleanSerializer ( ) ) ,
Map Util . entry ( Boolean . class , new BooleanSerializer ( ) ) ,
Map . entry ( byte . class , new NumberSerializer ( byte . class ) ) ,
Map Util . entry ( byte . class , new NumberSerializer ( byte . class ) ) ,
Map . entry ( Byte . class , new NumberSerializer ( Byte . class ) ) ,
Map Util . entry ( Byte . class , new NumberSerializer ( Byte . class ) ) ,
Map . entry ( short . class , new NumberSerializer ( short . class ) ) ,
Map Util . entry ( short . class , new NumberSerializer ( short . class ) ) ,
Map . entry ( Short . class , new NumberSerializer ( Short . class ) ) ,
Map Util . entry ( Short . class , new NumberSerializer ( Short . class ) ) ,
Map . entry ( int . class , new NumberSerializer ( int . class ) ) ,
Map Util . entry ( int . class , new NumberSerializer ( int . class ) ) ,
Map . entry ( Integer . class , new NumberSerializer ( Integer . class ) ) ,
Map Util . entry ( Integer . class , new NumberSerializer ( Integer . class ) ) ,
Map . entry ( long . class , new NumberSerializer ( long . class ) ) ,
Map Util . entry ( long . class , new NumberSerializer ( long . class ) ) ,
Map . entry ( Long . class , new NumberSerializer ( Long . class ) ) ,
Map Util . entry ( Long . class , new NumberSerializer ( Long . class ) ) ,
Map . entry ( float . class , new NumberSerializer ( float . class ) ) ,
Map Util . entry ( float . class , new NumberSerializer ( float . class ) ) ,
Map . entry ( Float . class , new NumberSerializer ( Float . class ) ) ,
Map Util . entry ( Float . class , new NumberSerializer ( Float . class ) ) ,
Map . entry ( double . class , new NumberSerializer ( double . class ) ) ,
Map Util . entry ( double . class , new NumberSerializer ( double . class ) ) ,
Map . entry ( Double . class , new NumberSerializer ( Double . class ) ) ,
Map Util . entry ( Double . class , new NumberSerializer ( Double . class ) ) ,
Map . entry ( char . class , new CharacterSerializer ( ) ) ,
Map Util . entry ( char . class , new CharacterSerializer ( ) ) ,
Map . entry ( Character . class , new CharacterSerializer ( ) ) ,
Map Util . entry ( Character . class , new CharacterSerializer ( ) ) ,
Map . entry ( String . class , new StringSerializer ( ) ) ,
Map Util . entry ( String . class , new StringSerializer ( ) ) ,
Map . entry ( BigInteger . class , new BigIntegerSerializer ( ) ) ,
Map Util . entry ( BigInteger . class , new BigIntegerSerializer ( ) ) ,
Map . entry ( BigDecimal . class , new BigDecimalSerializer ( ) ) ,
Map Util . entry ( BigDecimal . class , new BigDecimalSerializer ( ) ) ,
Map . entry ( LocalDate . class , new LocalDateSerializer ( ) ) ,
Map Util . entry ( LocalDate . class , new LocalDateSerializer ( ) ) ,
Map . entry ( LocalTime . class , new LocalTimeSerializer ( ) ) ,
Map Util . entry ( LocalTime . class , new LocalTimeSerializer ( ) ) ,
Map . entry ( LocalDateTime . class , new LocalDateTimeSerializer ( ) ) ,
Map Util . entry ( LocalDateTime . class , new LocalDateTimeSerializer ( ) ) ,
Map . entry ( Instant . class , new InstantSerializer ( ) ) ,
Map Util . entry ( Instant . class , new InstantSerializer ( ) ) ,
Map . entry ( UUID . class , new UuidSerializer ( ) ) ,
Map Util . entry ( UUID . class , new UuidSerializer ( ) ) ,
Map . entry ( File . class , new FileSerializer ( ) ) ,
Map Util . entry ( File . class , new FileSerializer ( ) ) ,
Map . entry ( Path . class , new PathSerializer ( ) ) ,
Map Util . entry ( Path . class , new PathSerializer ( ) ) ,
Map . entry ( URL . class , new UrlSerializer ( ) ) ,
Map Util . entry ( URL . class , new UrlSerializer ( ) ) ,
Map . entry ( URI . class , new UriSerializer ( ) )
Map Util . entry ( URI . class , new UriSerializer ( ) )
) ;
) ;
private final ConfigurationProperties properties ;
private final ConfigurationProperties properties ;
/ * *
/ * *
@ -101,18 +105,28 @@ final class SerializerSelector {
}
}
private Serializer < ? , ? > selectCustomSerializer ( AnnotatedType annotatedType ) {
private Serializer < ? , ? > selectCustomSerializer ( AnnotatedType annotatedType ) {
return findConfigurationElementSerializer ( annotatedType )
Optional < Serializer < ? , ? > > o = findConfigurationElementSerializer ( annotatedType ) ;
. or ( ( ) - > findSerializerFactoryForType ( annotatedType ) )
if ( o . isPresent ( ) ) return o . get ( ) ;
. or ( ( ) - > findSerializerForType ( annotatedType ) )
. or ( ( ) - > findSerializerOnType ( annotatedType ) )
o = findSerializerFactoryForType ( annotatedType ) ;
. or ( ( ) - > findMetaSerializerOnType ( annotatedType ) )
if ( o . isPresent ( ) ) return o . get ( ) ;
. or ( ( ) - > findSerializerByCondition ( annotatedType ) )
. orElse ( null ) ;
o = findSerializerForType ( annotatedType ) ;
if ( o . isPresent ( ) ) return o . get ( ) ;
o = findSerializerOnType ( annotatedType ) ;
if ( o . isPresent ( ) ) return o . get ( ) ;
o = findMetaSerializerOnType ( annotatedType ) ;
if ( o . isPresent ( ) ) return o . get ( ) ;
o = findSerializerByCondition ( annotatedType ) ;
return o . orElse ( null ) ;
}
}
private Optional < Serializer < ? , ? > > findConfigurationElementSerializer ( AnnotatedType annotatedType ) {
private Optional < Serializer < ? , ? > > findConfigurationElementSerializer ( AnnotatedType annotatedType ) {
// SerializeWith annotation on configuration elements
// SerializeWith annotation on configuration elements
final var annotation = element . annotation ( SerializeWith . class ) ;
final SerializeWith annotation = element . annotation ( SerializeWith . class ) ;
if ( ( annotation ! = null ) & & ( currentNesting = = annotation . nesting ( ) ) ) {
if ( ( annotation ! = null ) & & ( currentNesting = = annotation . nesting ( ) ) ) {
return Optional . of ( newSerializerFromAnnotation ( annotatedType , annotation ) ) ;
return Optional . of ( newSerializerFromAnnotation ( annotatedType , annotation ) ) ;
}
}
@ -121,11 +135,12 @@ final class SerializerSelector {
private Optional < Serializer < ? , ? > > findSerializerFactoryForType ( AnnotatedType annotatedType ) {
private Optional < Serializer < ? , ? > > findSerializerFactoryForType ( AnnotatedType annotatedType ) {
// Serializer factory registered for Type via configurations properties
// Serializer factory registered for Type via configurations properties
if ( ( annotatedType . getType ( ) instanceof Class < ? > cls ) & &
if ( ( annotatedType . getType ( ) instanceof Class < ? > ) & &
properties . getSerializerFactories ( ) . containsKey ( cls ) ) {
properties . getSerializerFactories ( ) . containsKey ( ( Class < ? > ) annotatedType . getType ( ) ) ) {
final var context = new SerializerContextImpl ( properties , element , annotatedType ) ;
Class < ? > cls = ( Class < ? > ) annotatedType . getType ( ) ;
final var factory = properties . getSerializerFactories ( ) . get ( cls ) ;
final SerializerContextImpl context = new SerializerContextImpl ( properties , element , annotatedType ) ;
final var serializer = factory . apply ( context ) ;
final Function < ? super SerializerContext , ? extends Serializer < ? , ? > > factory = properties . getSerializerFactories ( ) . get ( cls ) ;
final Serializer < ? , ? > serializer = factory . apply ( context ) ;
if ( serializer = = null ) {
if ( serializer = = null ) {
String msg = "Serializer factories must not return null." ;
String msg = "Serializer factories must not return null." ;
throw new ConfigurationException ( msg ) ;
throw new ConfigurationException ( msg ) ;
@ -137,8 +152,9 @@ final class SerializerSelector {
private Optional < Serializer < ? , ? > > findSerializerForType ( AnnotatedType annotatedType ) {
private Optional < Serializer < ? , ? > > findSerializerForType ( AnnotatedType annotatedType ) {
// Serializer registered for Type via configurations properties
// Serializer registered for Type via configurations properties
if ( ( annotatedType . getType ( ) instanceof Class < ? > cls ) & &
if ( ( annotatedType . getType ( ) instanceof Class < ? > ) & &
properties . getSerializers ( ) . containsKey ( cls ) ) {
properties . getSerializers ( ) . containsKey ( ( Class < ? > ) annotatedType . getType ( ) ) ) {
Class < ? > cls = ( Class < ? > ) annotatedType . getType ( ) ;
return Optional . of ( properties . getSerializers ( ) . get ( cls ) ) ;
return Optional . of ( properties . getSerializers ( ) . get ( cls ) ) ;
}
}
return Optional . empty ( ) ;
return Optional . empty ( ) ;
@ -146,9 +162,10 @@ final class SerializerSelector {
private Optional < Serializer < ? , ? > > findSerializerOnType ( AnnotatedType annotatedType ) {
private Optional < Serializer < ? , ? > > findSerializerOnType ( AnnotatedType annotatedType ) {
// SerializeWith annotation on type
// SerializeWith annotation on type
if ( ( annotatedType . getType ( ) instanceof Class < ? > cls ) & &
if ( ( annotatedType . getType ( ) instanceof Class < ? > ) & &
( cls . getDeclaredAnnotation ( SerializeWith . class ) ! = null ) ) {
( ( ( Class < ? > ) annotatedType . getType ( ) ) . getDeclaredAnnotation ( SerializeWith . class ) ! = null ) ) {
final var annotation = cls . getDeclaredAnnotation ( SerializeWith . class ) ;
final Class < ? > cls = ( Class < ? > ) annotatedType . getType ( ) ;
final SerializeWith annotation = cls . getDeclaredAnnotation ( SerializeWith . class ) ;
return Optional . of ( newSerializerFromAnnotation ( annotatedType , annotation ) ) ;
return Optional . of ( newSerializerFromAnnotation ( annotatedType , annotation ) ) ;
}
}
return Optional . empty ( ) ;
return Optional . empty ( ) ;
@ -156,10 +173,11 @@ final class SerializerSelector {
private Optional < Serializer < ? , ? > > findMetaSerializerOnType ( AnnotatedType annotatedType ) {
private Optional < Serializer < ? , ? > > findMetaSerializerOnType ( AnnotatedType annotatedType ) {
// SerializeWith meta annotation on type
// SerializeWith meta annotation on type
if ( ( annotatedType . getType ( ) instanceof Class < ? > cls ) ) {
if ( annotatedType . getType ( ) instanceof Class < ? > ) {
for ( final var meta : cls . getDeclaredAnnotations ( ) ) {
final Class < ? > cls = ( Class < ? > ) annotatedType . getType ( ) ;
final var metaType = meta . annotationType ( ) ;
for ( final Annotation meta : cls . getDeclaredAnnotations ( ) ) {
final var annotation = metaType . getDeclaredAnnotation ( SerializeWith . class ) ;
final Class < ? extends Annotation > metaType = meta . annotationType ( ) ;
final SerializeWith annotation = metaType . getDeclaredAnnotation ( SerializeWith . class ) ;
if ( annotation ! = null )
if ( annotation ! = null )
return Optional . of ( newSerializerFromAnnotation ( annotatedType , annotation ) ) ;
return Optional . of ( newSerializerFromAnnotation ( annotatedType , annotation ) ) ;
}
}
@ -169,7 +187,7 @@ final class SerializerSelector {
private Optional < Serializer < ? , ? > > findSerializerByCondition ( AnnotatedType annotatedType ) {
private Optional < Serializer < ? , ? > > findSerializerByCondition ( AnnotatedType annotatedType ) {
// Serializer registered for condition via configurations properties
// Serializer registered for condition via configurations properties
for ( var entry : properties . getSerializersByCondition ( ) . entrySet ( ) ) {
for ( Map. Entry < Predicate < ? super Type > , Serializer < ? , ? > > entry : properties . getSerializersByCondition ( ) . entrySet ( ) ) {
if ( entry . getKey ( ) . test ( annotatedType . getType ( ) ) )
if ( entry . getKey ( ) . test ( annotatedType . getType ( ) ) )
return Optional . of ( entry . getValue ( ) ) ;
return Optional . of ( entry . getValue ( ) ) ;
}
}
@ -180,7 +198,7 @@ final class SerializerSelector {
AnnotatedType annotatedType ,
AnnotatedType annotatedType ,
SerializeWith annotation
SerializeWith annotation
) {
) {
final var context = new SerializerContextImpl ( properties , element , annotatedType ) ;
final SerializerContextImpl context = new SerializerContextImpl ( properties , element , annotatedType ) ;
return Serializers . newCustomSerializer ( annotation . serializer ( ) , context ) ;
return Serializers . newCustomSerializer ( annotation . serializer ( ) , context ) ;
}
}
@ -191,7 +209,7 @@ final class SerializerSelector {
if ( Reflect . isEnumType ( cls ) ) {
if ( Reflect . isEnumType ( cls ) ) {
// The following cast won't fail because we just checked that it's an enum.
// The following cast won't fail because we just checked that it's an enum.
@SuppressWarnings ( "unchecked" )
@SuppressWarnings ( "unchecked" )
final var enumType = ( Class < ? extends Enum < ? > > ) cls ;
final Class< ? extends Enum < ? > > enumType = ( Class < ? extends Enum < ? > > ) cls ;
return new Serializers . EnumSerializer ( enumType ) ;
return new Serializers . EnumSerializer ( enumType ) ;
}
}
if ( Reflect . isArrayType ( cls ) )
if ( Reflect . isArrayType ( cls ) )
@ -225,34 +243,34 @@ final class SerializerSelector {
} else if ( elementType = = double . class ) {
} else if ( elementType = = double . class ) {
return new PrimitiveDoubleArraySerializer ( ) ;
return new PrimitiveDoubleArraySerializer ( ) ;
}
}
var elementSerializer = selectForType ( annotatedElementType ) ;
Serializer< ? , ? > elementSerializer = selectForType ( annotatedElementType ) ;
var inputNulls = properties . inputNulls ( ) ;
boolean inputNulls = properties . inputNulls ( ) ;
var outputNulls = properties . outputNulls ( ) ;
boolean outputNulls = properties . outputNulls ( ) ;
return new ArraySerializer < > ( elementType , elementSerializer , outputNulls , inputNulls ) ;
return new ArraySerializer < > ( elementType , elementSerializer , outputNulls , inputNulls ) ;
}
}
private Serializer < ? , ? > selectForParameterizedType ( AnnotatedParameterizedType annotatedType ) {
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 ParameterizedType type = ( ParameterizedType ) annotatedType . getType ( ) ;
final var rawType = ( Class < ? > ) type . getRawType ( ) ;
final Class< ? > rawType = ( Class < ? > ) type . getRawType ( ) ;
final var typeArgs = annotatedType . getAnnotatedActualTypeArguments ( ) ;
final AnnotatedType[ ] typeArgs = annotatedType . getAnnotatedActualTypeArguments ( ) ;
final var inputNulls = properties . inputNulls ( ) ;
final boolean inputNulls = properties . inputNulls ( ) ;
final var outputNulls = properties . outputNulls ( ) ;
final boolean outputNulls = properties . outputNulls ( ) ;
if ( Reflect . isListType ( rawType ) ) {
if ( Reflect . isListType ( rawType ) ) {
var elementSerializer = selectForType ( typeArgs [ 0 ] ) ;
Serializer< ? , ? > 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 = selectForType ( typeArgs [ 0 ] ) ;
Serializer< ? , ? > 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 ) ;
} else if ( Reflect . isMapType ( rawType ) ) {
} else if ( Reflect . isMapType ( rawType ) ) {
if ( ( typeArgs [ 0 ] . getType ( ) instanceof Class < ? > cls ) & &
if ( ( typeArgs [ 0 ] . getType ( ) instanceof Class < ? > ) & &
( DEFAULT_SERIALIZERS . containsKey ( cls ) | |
( DEFAULT_SERIALIZERS . containsKey ( ( Class < ? > ) typeArgs [ 0 ] . getType ( ) ) | |
Reflect . isEnumType ( cls ) ) ) {
Reflect . isEnumType ( ( Class < ? > ) typeArgs [ 0 ] . getType ( ) ) ) ) {
var keySerializer = selectForClass ( typeArgs [ 0 ] ) ;
Serializer< ? , ? > keySerializer = selectForClass ( typeArgs [ 0 ] ) ;
var valSerializer = selectForType ( typeArgs [ 1 ] ) ;
Serializer< ? , ? > 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 ) +
@ -266,6 +284,6 @@ final class SerializerSelector {
}
}
private String baseExceptionMessage ( Type type ) {
private String baseExceptionMessage ( Type type ) {
return "Cannot select serializer for type ' %s'.\n". formatted ( type ) ;
return "Cannot select serializer for type ' " + type + "'.\n" ;
}
}
}
}