From 0a291fe92255bec329c15be0ce94cd771d07d278 Mon Sep 17 00:00:00 2001 From: Exlll Date: Sat, 6 Aug 2022 10:53:36 +0200 Subject: [PATCH] Move SerializerMapper functionality to TypeSerializer --- .../configlib/ConfigurationSerializer.java | 3 +- .../de/exlll/configlib/SerializerMapper.java | 77 ----------------- .../exlll/configlib/SerializerSelector.java | 4 +- .../de/exlll/configlib/TypeSerializer.java | 19 ++++- ...apperTest.java => TypeSerializerTest.java} | 82 ++++--------------- 5 files changed, 40 insertions(+), 145 deletions(-) delete mode 100644 configlib-core/src/main/java/de/exlll/configlib/SerializerMapper.java rename configlib-core/src/test/java/de/exlll/configlib/{SerializerMapperTest.java => TypeSerializerTest.java} (69%) diff --git a/configlib-core/src/main/java/de/exlll/configlib/ConfigurationSerializer.java b/configlib-core/src/main/java/de/exlll/configlib/ConfigurationSerializer.java index 828afe9..4cbe819 100644 --- a/configlib-core/src/main/java/de/exlll/configlib/ConfigurationSerializer.java +++ b/configlib-core/src/main/java/de/exlll/configlib/ConfigurationSerializer.java @@ -3,6 +3,7 @@ package de.exlll.configlib; import de.exlll.configlib.TypeComponent.ConfigurationField; import java.lang.reflect.Field; +import java.util.List; import java.util.Map; final class ConfigurationSerializer extends TypeSerializer { @@ -51,7 +52,7 @@ final class ConfigurationSerializer extends TypeSerializer components() { + protected List components() { return FieldExtractors.CONFIGURATION.extract(type) .filter(properties.getFieldFilter()) .map(ConfigurationField::new) diff --git a/configlib-core/src/main/java/de/exlll/configlib/SerializerMapper.java b/configlib-core/src/main/java/de/exlll/configlib/SerializerMapper.java deleted file mode 100644 index 10a487b..0000000 --- a/configlib-core/src/main/java/de/exlll/configlib/SerializerMapper.java +++ /dev/null @@ -1,77 +0,0 @@ -package de.exlll.configlib; - -import java.lang.reflect.Field; -import java.lang.reflect.RecordComponent; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static de.exlll.configlib.Validator.requireNonNull; - -/** - * A mapper that maps field or component names to serializers that are selected based on - * the field or component type, respectively. - */ -final class SerializerMapper { - private final Class type; - private final ConfigurationProperties properties; - private final SerializerSelector selector; - - SerializerMapper(Class type, ConfigurationProperties properties) { - this.type = requireNonNull(type, "type"); - this.properties = requireNonNull(properties, "configuration properties"); - this.selector = new SerializerSelector(properties); - requireConfigurationOrRecord(); - } - - private void requireConfigurationOrRecord() { - if (!type.isRecord() && !Reflect.isConfiguration(type)) { - String msg = "Type '%s' must be a configuration or record type." - .formatted(type.getSimpleName()); - throw new ConfigurationException(msg); - } - } - - public Map> buildSerializerMap() { - return type.isRecord() - ? buildSerializerMapForRecord() - : buildSerializerMapForConfiguration(); - - } - - private Map> buildSerializerMapForRecord() { - return tryBuildSerializerMap( - Arrays.stream(type.getRecordComponents()), - RecordComponent::getName, - RecordComponent::getGenericType - ); - } - - private Map> buildSerializerMapForConfiguration() { - return tryBuildSerializerMap(filterFields(), Field::getName, Field::getGenericType); - } - - private Map> tryBuildSerializerMap( - Stream stream, - Function nameExtractor, - Function typeExtractor - ) { - try { - return stream.collect(Collectors.toMap( - nameExtractor, - element -> selector.select(typeExtractor.apply(element)) - )); - } catch (StackOverflowError error) { - String msg = "Recursive type definitions are not supported."; - throw new ConfigurationException(msg, error); - } - } - - private Stream filterFields() { - return FieldExtractors.CONFIGURATION.extract(type) - .filter(properties.getFieldFilter()); - } -} 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 c25e685..96e6e58 100644 --- a/configlib-core/src/main/java/de/exlll/configlib/SerializerSelector.java +++ b/configlib-core/src/main/java/de/exlll/configlib/SerializerSelector.java @@ -16,6 +16,8 @@ import java.time.LocalTime; import java.util.Map; import java.util.UUID; +import static de.exlll.configlib.Validator.requireNonNull; + final class SerializerSelector { private static final Map, Serializer> DEFAULT_SERIALIZERS = Map.ofEntries( Map.entry(boolean.class, new BooleanSerializer()), @@ -50,7 +52,7 @@ final class SerializerSelector { private final ConfigurationProperties properties; public SerializerSelector(ConfigurationProperties properties) { - this.properties = properties; + this.properties = requireNonNull(properties, "configuration properties"); } public Serializer select(Type type) { 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 ff9c8ff..125fe68 100644 --- a/configlib-core/src/main/java/de/exlll/configlib/TypeSerializer.java +++ b/configlib-core/src/main/java/de/exlll/configlib/TypeSerializer.java @@ -1,7 +1,9 @@ package de.exlll.configlib; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static de.exlll.configlib.Validator.requireNonNull; @@ -17,7 +19,7 @@ sealed abstract class TypeSerializer> this.type = requireNonNull(type, "type"); this.properties = requireNonNull(properties, "configuration properties"); this.formatter = properties.getNameFormatter(); - this.serializers = new SerializerMapper(type, properties).buildSerializerMap(); + this.serializers = buildSerializerMap(); requireSerializableComponents(); } @@ -30,6 +32,19 @@ sealed abstract class TypeSerializer> : new ConfigurationSerializer<>(type, properties); } + Map> buildSerializerMap() { + final var selector = new SerializerSelector(properties); + try { + return components().stream().collect(Collectors.toMap( + TypeComponent::name, + component -> selector.select(component.genericType()) + )); + } catch (StackOverflowError error) { + String msg = "Recursive type definitions are not supported."; + throw new ConfigurationException(msg, error); + } + } + @Override public final Map serialize(T element) { final Map result = new LinkedHashMap<>(); @@ -83,7 +98,7 @@ sealed abstract class TypeSerializer> protected abstract String baseDeserializeExceptionMessage(TC component, Object value); - protected abstract Iterable components(); + protected abstract List components(); abstract T newDefaultInstance(); } diff --git a/configlib-core/src/test/java/de/exlll/configlib/SerializerMapperTest.java b/configlib-core/src/test/java/de/exlll/configlib/TypeSerializerTest.java similarity index 69% rename from configlib-core/src/test/java/de/exlll/configlib/SerializerMapperTest.java rename to configlib-core/src/test/java/de/exlll/configlib/TypeSerializerTest.java index 2bd7c79..041e6f9 100644 --- a/configlib-core/src/test/java/de/exlll/configlib/SerializerMapperTest.java +++ b/configlib-core/src/test/java/de/exlll/configlib/TypeSerializerTest.java @@ -1,5 +1,6 @@ package de.exlll.configlib; +import de.exlll.configlib.Serializers.*; import de.exlll.configlib.configurations.ExampleConfigurationA2; import de.exlll.configlib.configurations.ExampleConfigurationB1; import de.exlll.configlib.configurations.ExampleConfigurationB2; @@ -14,71 +15,39 @@ import java.util.Set; import java.util.UUID; import java.util.function.Consumer; -import static de.exlll.configlib.Serializers.*; import static de.exlll.configlib.TestUtils.assertThrowsConfigurationException; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -class SerializerMapperTest { - private static SerializerMapper newMapper(Class cls) { - return newMapper(cls, builder -> {}); - } - - private static SerializerMapper newMapper( - Class cls, +class TypeSerializerTest { + private static TypeSerializer newTypeSerializer( + Class type, Consumer> propertiesConfigurer ) { var builder = ConfigurationProperties.newBuilder(); builder.addSerializer(Point.class, TestUtils.POINT_SERIALIZER); propertiesConfigurer.accept(builder); - return new SerializerMapper(cls, builder.build()); - } - - @Test - void requireConfigurationOrRecord() { - ConfigurationProperties properties = ConfigurationProperties.newBuilder().build(); - TestUtils.assertThrowsConfigurationException( - () -> new SerializerMapper(Object.class, properties), - "Type 'Object' must be a configuration or record type." - ); + ConfigurationProperties properties = builder.build(); + return TypeSerializer.newSerializerFor(type, properties); } - @Test - void buildSerializerMapForConfigurationFiltersFields() { - Map> serializers = newMapper(ExampleConfigurationA2.class) - .buildSerializerMap(); - - assertThat(serializers.get("a1_staticFinalInt"), nullValue()); - assertThat(serializers.get("a1_staticInt"), nullValue()); - assertThat(serializers.get("a1_finalInt"), nullValue()); - assertThat(serializers.get("a1_transientInt"), nullValue()); - assertThat(serializers.get("a1_ignoredInt"), nullValue()); - assertThat(serializers.get("a1_ignoredString"), nullValue()); - assertThat(serializers.get("a1_ignoredListString"), nullValue()); - - assertThat(serializers.get("a2_staticFinalInt"), nullValue()); - assertThat(serializers.get("a2_staticInt"), nullValue()); - assertThat(serializers.get("a2_finalInt"), nullValue()); - assertThat(serializers.get("a2_transientInt"), nullValue()); - assertThat(serializers.get("a2_ignoredInt"), nullValue()); - assertThat(serializers.get("a2_ignoredString"), nullValue()); - assertThat(serializers.get("a2_ignoredListString"), nullValue()); + private static TypeSerializer newTypeSerializer(Class type) { + return newTypeSerializer(type, builder -> {}); } @Test - void buildSerializerMapForConfigurationIgnoresFormatter() { - Map> serializers = newMapper( + void buildSerializerMapUsesComponentName() { + Map> serializers = newTypeSerializer( ExampleConfigurationA2.class, - props -> props.setNameFormatter(NameFormatters.UPPER_UNDERSCORE) + builder -> builder.setNameFormatter(NameFormatters.UPPER_UNDERSCORE) ).buildSerializerMap(); - assertThat(serializers.get("A2_PRIM_BOOL"), nullValue()); assertThat(serializers.get("a2_primBool"), instanceOf(BooleanSerializer.class)); } @Test void buildSerializerMapForConfiguration() { - Map> serializers = newMapper(ExampleConfigurationA2.class) + Map> serializers = newTypeSerializer(ExampleConfigurationA2.class) .buildSerializerMap(); assertThat(serializers.get("a2_primBool"), instanceOf(BooleanSerializer.class)); assertThat(serializers.get("a2_refChar"), instanceOf(CharacterSerializer.class)); @@ -116,22 +85,7 @@ class SerializerMapperTest { assertThat(serializers.get("a2_point"), sameInstance(TestUtils.POINT_SERIALIZER)); } - private record R1(int integer, boolean bool) {} - - @Test - void buildSerializerMapForRecordIgnoresFormatter() { - Map> serializers = newMapper( - R1.class, - props -> props.setNameFormatter(NameFormatters.UPPER_UNDERSCORE) - ).buildSerializerMap(); - - assertThat(serializers.get("INTEGER"), nullValue()); - assertThat(serializers.get("BOOL"), nullValue()); - assertThat(serializers.get("integer"), instanceOf(NumberSerializer.class)); - assertThat(serializers.get("bool"), instanceOf(BooleanSerializer.class)); - } - - private record R2( + private record R1( boolean primBool, Character refChar, String string, @@ -148,7 +102,7 @@ class SerializerMapperTest { @Test void buildSerializerMapForRecord() { - Map> serializers = newMapper(R2.class) + Map> serializers = newTypeSerializer(R1.class) .buildSerializerMap(); assertThat(serializers.get("primBool"), instanceOf(BooleanSerializer.class)); assertThat(serializers.get("refChar"), instanceOf(CharacterSerializer.class)); @@ -199,7 +153,7 @@ class SerializerMapperTest { @Test void buildSerializerMapForConfigurationPreventsRecursiveDefinitions() { assertThrowsConfigurationException( - () -> newMapper(Recursive1.class).buildSerializerMap(), + () -> newTypeSerializer(Recursive1.class), "Recursive type definitions are not supported." ); } @@ -213,13 +167,13 @@ class SerializerMapperTest { @Test void buildSerializerMapForRecordPreventsRecursiveDefinitions() { assertThrowsConfigurationException( - () -> newMapper(RecursiveRecord1.class).buildSerializerMap(), + () -> newTypeSerializer(RecursiveRecord1.class), "Recursive type definitions are not supported." ); assertThrowsConfigurationException( - () -> newMapper(RecursiveRecord3.class).buildSerializerMap(), + () -> newTypeSerializer(RecursiveRecord3.class), "Recursive type definitions are not supported." ); } -} \ No newline at end of file +}