Skip to content

Commit

Permalink
Use Type instead of Class<?> in ClassSerializer (closes #3)
Browse files Browse the repository at this point in the history
  • Loading branch information
hevav committed Oct 21, 2023
1 parent cacf98d commit bfbf01e
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ public Builder registerSerializer(Collection<ClassSerializer<?, ?>> serializers)
}

public Builder registerSerializer(ClassSerializer<?, ?> serializer) {
this.registeredSerializers.put(serializer.getToType(), serializer);
this.registeredSerializers.put(serializer.getToClass(), serializer);
return this;
}

Expand Down
18 changes: 16 additions & 2 deletions src/main/java/net/elytrium/serializer/custom/ClassSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,28 @@
public abstract class ClassSerializer<T, F> {

private final Class<T> toClass;
private final Type toType;
private final Class<F> fromClass;
private final Type fromType;

@SuppressWarnings("unchecked")
protected ClassSerializer() {
Type[] actualTypeArguments = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
this.toClass = actualTypeArguments[0] instanceof Class<?>
? (Class<T>) actualTypeArguments[0]
: (Class<T>) ((ParameterizedType) actualTypeArguments[0]).getRawType();
this.toType = actualTypeArguments[0];
this.fromClass = actualTypeArguments[1] instanceof Class<?>
? (Class<F>) actualTypeArguments[1]
: (Class<F>) ((ParameterizedType) actualTypeArguments[1]).getRawType();
this.fromType = actualTypeArguments[1];
}

protected ClassSerializer(Class<T> toClass, Class<F> fromClass) {
this.toClass = toClass;
this.toType = toClass;
this.fromClass = fromClass;
this.fromType = fromClass;
}

public F serialize(T from) {
Expand All @@ -49,11 +55,19 @@ public T deserialize(F from) {
throw new UnsupportedOperationException();
}

public Class<T> getToType() {
public Class<T> getToClass() {
return this.toClass;
}

public Class<F> getFromType() {
public Type getToType() {
return this.toType;
}

public Class<F> getFromClass() {
return this.fromClass;
}

public Type getFromType() {
return this.fromType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,19 @@ public Object readNode(Object holder, Field node) {
if (serializer != null) {
try {
ClassSerializer<?, Object> classSerializer = this.config.getAndCacheSerializer(serializer);
if (clazz.isAssignableFrom(classSerializer.getToType())) {
if (clazz.isAssignableFrom(classSerializer.getToClass())) {
serializerStack.add(classSerializer);
type = classSerializer.getFromType();
clazz = classSerializer.getFromType();
clazz = classSerializer.getFromClass();
}
} catch (ReflectiveOperationException e) {
throw new ReflectionException(e);
}
}

clazz = this.fillSerializerStack(serializerStack, clazz);
if (!serializerStack.isEmpty()) {
type = clazz;
Type typeSerialized = this.fillSerializerStack(serializerStack, clazz);
if (!serializerStack.isEmpty() && typeSerialized != null) {
type = typeSerialized;
}

try {
Expand All @@ -152,29 +152,31 @@ public Object readNode(Object holder, Field node) {
}
}

protected Class<?> fillSerializerStack(Deque<ClassSerializer<?, Object>> serializerStack, Class<?> clazz) {
protected Type fillSerializerStack(Deque<ClassSerializer<?, Object>> serializerStack, Class<?> clazz) {
Type type = null;
while (true) {
ClassSerializer<?, Object> classSerializer = this.config.getRegisteredSerializer(clazz);
if (classSerializer == null || !clazz.isAssignableFrom(classSerializer.getToType())) {
if (classSerializer == null || !clazz.isAssignableFrom(classSerializer.getToClass())) {
break;
}

serializerStack.add(classSerializer);
clazz = classSerializer.getFromType();
clazz = classSerializer.getFromClass();
type = classSerializer.getFromType();

if (classSerializer.getToType() == classSerializer.getFromType()) {
break;
}
}

return clazz;
return type;
}

protected Object readAndDeserializeByType(@Nullable Field owner, Object holder, Type type, Deque<ClassSerializer<?, Object>> serializerStack) {
Object value = this.readByType(owner, holder, type);
while (!serializerStack.isEmpty()) {
ClassSerializer<?, Object> classSerializer = serializerStack.pop();
if (classSerializer.getFromType().isInstance(value)) {
if (classSerializer.getFromClass().isInstance(value)) {
value = classSerializer.deserialize(value);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import net.elytrium.serializer.placeholders.Placeholders;
import net.elytrium.serializer.utils.GenericUtils;

@SuppressWarnings({"SizeReplaceableByIsEmpty", "StringRepeatCanBeUsed"}) // Ignore modern methods, because we support up to Java 8.
@SuppressWarnings({"StringRepeatCanBeUsed"}) // Ignore modern methods, because we support up to Java 8.
public class YamlReader extends AbstractReader {

private static final Logger LOGGER = Logger.getLogger(YamlReader.class.getName());
Expand Down Expand Up @@ -503,16 +503,16 @@ private void readMapEntry(@Nullable Field owner, Type keyType, Type valueType, S
}
} else {
Deque<ClassSerializer<?, Object>> serializerStack = new ArrayDeque<>(Math.min(16, this.config.getRegisteredSerializers() + 1/*See AbstractReader#readNode*/));
Class<?> clazz = this.fillSerializerStack(serializerStack, keyClazz);
Type type = this.fillSerializerStack(serializerStack, keyClazz);
if (serializerStack.isEmpty()) {
throw new IllegalStateException("Class " + keyClazz + " for map key are not supported yet!");
}

if (Map.class.isAssignableFrom(clazz) || Collection.class.isAssignableFrom(clazz)) {
throw new IllegalStateException("Class " + clazz + " for map key is not supported!");
if (!(type instanceof Class<?>) || Map.class.isAssignableFrom((Class<?>) type) || Collection.class.isAssignableFrom((Class<?>) type)) {
throw new IllegalStateException("Class " + type + " for map key is not supported!");
}

key = this.readAndDeserializeByType(owner, null, clazz, serializerStack);
key = this.readAndDeserializeByType(owner, null, type, serializerStack);
}
} else {
throw new IllegalStateException("Type " + keyType + " for map key are not supported yet!");
Expand Down
33 changes: 32 additions & 1 deletion src/test/java/net/elytrium/serializer/SerializerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
Expand Down Expand Up @@ -140,6 +141,7 @@ void testConfig() throws IOException {
);
Assertions.assertEquals("value 1 value 2", Placeholders.replace(settings.anotherStringWithPlaceholders, "value 1", "value 2"));
Assertions.assertEquals("PLACEHOLDER another-placeholder", settings.anotherStringWithPlaceholders);
Assertions.assertEquals(1, settings.testListSection.data.originalList.size());
Assertions.assertEquals(2, settings.prepend.sameLine.append.nestedLists.size());
Assertions.assertEquals(2, settings.objectListWithMaps.size());
Assertions.assertEquals(3, settings.listOfString2ObjectMap.size());
Expand Down Expand Up @@ -298,7 +300,8 @@ public String serialize(String from) {
public String deserialize(String from) {
return from.trim().isEmpty() ? null : from;
}
}).registerSerializer(new PathSerializer()).setCommentValueIndent(1).setLineSeparator("\n").build();
}).registerSerializer(new PathSerializer()).registerSerializer(new TestListSerializer())
.setCommentValueIndent(1).setLineSeparator("\n").build();

Settings() {
super(Settings.CONFIG);
Expand Down Expand Up @@ -340,6 +343,8 @@ public String deserialize(String from) {
@RegisterPlaceholders(value = {"PLACEHOLDER", "another-placeholder"}, wrapWithBraces = false)
public String anotherStringWithPlaceholders = "PLACEHOLDER another-placeholder";

public TestListSection testListSection = new TestListSection();

@MapType(HashMap.class)
public Map<Integer, String> int2StringMap = SerializerTest.map(1, "v1", 15555, "v2", 44, "v3");

Expand Down Expand Up @@ -590,6 +595,19 @@ public ExternalDeserializedClass deserialize(Map<String, Object> from) {
}
}

public static class TestListData {
private final List<String> originalList;

public TestListData(List<String> originalList) {
this.originalList = new ArrayList<>(originalList);
}
}

public static class TestListSection {

public final TestListData data = new TestListData(List.of("test"));
}

public static class DateSerializer extends ClassSerializer<Date, Long> {

public DateSerializer() {
Expand Down Expand Up @@ -624,6 +642,19 @@ public Path deserialize(String from) {
}
}

public static class TestListSerializer extends ClassSerializer<TestListData, List<String>> {

@Override
public List<String> serialize(TestListData from) {
return from.originalList;
}

@Override
public TestListData deserialize(List<String> from) {
return new TestListData(from);
}
}

private enum RegularEnum {

ENUM_VALUE_1,
Expand Down
3 changes: 3 additions & 0 deletions src/test/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ regular-deque:
string-with-placeholders: "This is {TEST} with {TEST2}"
string-with-placeholders-2: "This is {test} with {test2}"
another-string-with-placeholders: "PLACEHOLDER another-placeholder"
test-list-section:
data:
- "test"
int-2-string-map:
1: "v1"
15555: "v2"
Expand Down

0 comments on commit bfbf01e

Please sign in to comment.