diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/Tag.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/Tag.java index ccb2d93..1b89d95 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/Tag.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/Tag.java @@ -43,7 +43,7 @@ * */ @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.FIELD}) +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.RECORD_COMPONENT}) public @interface Tag { /** * Specifies the Path expression indicating the location of the XML data for serialization and deserialization. diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/XjxSerdes.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/XjxSerdes.java index 2f796fb..7f255ff 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/XjxSerdes.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/XjxSerdes.java @@ -1,18 +1,18 @@ package io.jonasg.xjx.serdes; +import java.io.Reader; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; + import io.jonasg.xjx.sax.SaxParser; import io.jonasg.xjx.serdes.deserialize.MapOf; import io.jonasg.xjx.serdes.deserialize.MapRootSaxHandler; import io.jonasg.xjx.serdes.deserialize.PathBasedSaxHandler; import io.jonasg.xjx.serdes.deserialize.PathWriterIndexFactory; import io.jonasg.xjx.serdes.deserialize.XjxDeserializationException; -import io.jonasg.xjx.serdes.seraialize.XmlNodeStructureFactory; -import io.jonasg.xjx.serdes.seraialize.XmlStringBuilder; - -import java.io.Reader; -import java.io.StringReader; -import java.util.HashMap; -import java.util.Map; +import io.jonasg.xjx.serdes.serialize.XmlNodeStructureFactory; +import io.jonasg.xjx.serdes.serialize.XmlStringBuilder; /** * XjxSerdes provides functionality for serializing and deserializing objects to and from XML. diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapRootSaxHandler.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapRootSaxHandler.java index e9e0530..8f5cbc5 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapRootSaxHandler.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapRootSaxHandler.java @@ -1,14 +1,14 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.sax.Attribute; -import io.jonasg.xjx.sax.SaxHandler; - import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import io.jonasg.xjx.sax.Attribute; +import io.jonasg.xjx.sax.SaxHandler; + public class MapRootSaxHandler implements SaxHandler { private final LinkedList> mapsStack; diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapWithTypeInfo.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapWithTypeInfo.java index 8774c2a..0ce1fba 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapWithTypeInfo.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/MapWithTypeInfo.java @@ -1,6 +1,5 @@ package io.jonasg.xjx.serdes.deserialize; -import java.util.HashMap; import java.util.Map; public record MapWithTypeInfo(Map map, Class valueType) { diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathBasedSaxHandler.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathBasedSaxHandler.java index f992917..e8627bc 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathBasedSaxHandler.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathBasedSaxHandler.java @@ -1,15 +1,15 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.sax.Attribute; -import io.jonasg.xjx.sax.SaxHandler; -import io.jonasg.xjx.serdes.Path; - import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.function.Function; +import io.jonasg.xjx.sax.Attribute; +import io.jonasg.xjx.sax.SaxHandler; +import io.jonasg.xjx.serdes.Path; + public class PathBasedSaxHandler implements SaxHandler { private final Function> indexSupplier; diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathWriterIndexFactory.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathWriterIndexFactory.java index b7b1820..63c4b1a 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathWriterIndexFactory.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/PathWriterIndexFactory.java @@ -1,12 +1,5 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Path; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.TypeMappers; -import io.jonasg.xjx.serdes.deserialize.accessor.FieldAccessor; -import io.jonasg.xjx.serdes.reflector.FieldReflector; -import io.jonasg.xjx.serdes.reflector.TypeReflector; - import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -24,9 +17,16 @@ import java.util.Set; import java.util.function.Supplier; +import io.jonasg.xjx.serdes.Path; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.TypeMappers; +import io.jonasg.xjx.serdes.deserialize.accessor.FieldAccessor; +import io.jonasg.xjx.serdes.reflector.FieldReflector; +import io.jonasg.xjx.serdes.reflector.TypeReflector; + public class PathWriterIndexFactory { - private static final List> BASIC_TYPES = List.of( + public static final List> BASIC_TYPES = List.of( String.class, Integer.class, Boolean.class, boolean.class, Long.class, long.class, BigDecimal.class, Double.class, double.class, char.class, Character.class, LocalDate.class, LocalDateTime.class, ZonedDateTime.class); private final Map, Object> collectionCacheType = new HashMap<>(); diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/TypedValueMapSaxHandler.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/TypedValueMapSaxHandler.java index 457d207..4831312 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/TypedValueMapSaxHandler.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/TypedValueMapSaxHandler.java @@ -1,13 +1,13 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.sax.Attribute; -import io.jonasg.xjx.sax.SaxHandler; - import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import io.jonasg.xjx.sax.Attribute; +import io.jonasg.xjx.sax.SaxHandler; + public class TypedValueMapSaxHandler implements SaxHandler { private final LinkedList> mapsStack; diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/ReflectiveFieldAccessor.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/ReflectiveFieldAccessor.java index 74d420c..66be742 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/ReflectiveFieldAccessor.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/ReflectiveFieldAccessor.java @@ -1,9 +1,9 @@ package io.jonasg.xjx.serdes.deserialize.accessor; -import io.jonasg.xjx.serdes.reflector.FieldReflector; - import java.util.function.Function; +import io.jonasg.xjx.serdes.reflector.FieldReflector; + public class ReflectiveFieldAccessor implements FieldAccessor { private final FieldReflector field; diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/SetterFieldAccessor.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/SetterFieldAccessor.java index 1e19380..5d14fb6 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/SetterFieldAccessor.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/deserialize/accessor/SetterFieldAccessor.java @@ -1,11 +1,11 @@ package io.jonasg.xjx.serdes.deserialize.accessor; -import io.jonasg.xjx.serdes.reflector.FieldReflector; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import io.jonasg.xjx.serdes.reflector.FieldReflector; + public class SetterFieldAccessor implements FieldAccessor { private final Object instance; diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceField.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceField.java index 1a8437d..5332fde 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceField.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceField.java @@ -35,6 +35,10 @@ public Class type() { return fieldReflector.type(); } + public InstanceReflector reflect() { + return new InstanceReflector<>(getValue()); + } + @Override public String toString() { return new StringJoiner(", ", InstanceField.class.getSimpleName() + "[", "]") diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceReflector.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceReflector.java index a81cea6..383da73 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceReflector.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/reflector/InstanceReflector.java @@ -54,13 +54,17 @@ public void setField(String fieldName, Object value) { .ifPresent(f -> f.set(instance, value)); } - public List fields(Predicate predicate) { - return typeReflector.fields() - .stream() - .map(f -> new InstanceField(f, instance)) - .filter(predicate) - .toList(); - } + public List fields(Predicate predicate) { + return typeReflector.fields() + .stream() + .map(f -> new InstanceField(f, instance)) + .filter(predicate) + .toList(); + } + + public List fields() { + return fields(f -> true); + } public T instance() { return instance; diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlNodeStructureFactory.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlNodeStructureFactory.java deleted file mode 100644 index 7b5ab18..0000000 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlNodeStructureFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.jonasg.xjx.serdes.seraialize; - -import io.jonasg.xjx.serdes.Section; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.Path; -import io.jonasg.xjx.serdes.reflector.InstanceField; -import io.jonasg.xjx.serdes.reflector.Reflector; - -public class XmlNodeStructureFactory { - - public XmlNode build(T data) { - return getXmlNode(Path.parse("/"), data, null); - } - - private XmlNode getXmlNode(Path parentPath, T data, XmlNode node) { - if (data != null) { - for (InstanceField field : Reflector.reflect(data) - .fields(f -> f.hasAnnotation(Tag.class))) { - node = buildNodeForField(field, parentPath, node); - } - } - return node; - } - - private XmlNode buildNodeForField(InstanceField field, Path parentPath, XmlNode rootNode) { - var tag = field.getAnnotation(Tag.class); - var path = parentPath.append(Path.parse(tag.path())); - if (rootNode == null) { - rootNode = new XmlNode(path.getRoot()); - } - var node = rootNode; - for (int i = 1; i < path.size(); i++) { - Section section = path.getSection(i); - if (section.isLeaf()) { - handleLeafNode(field, section, tag, node); - } else { - node = node.addNode(section.name()); - } - } - return getXmlNode(path, field.getValue(), rootNode); - } - - private static void handleLeafNode(InstanceField field, Section section, Tag tag, XmlNode node) { - if (!tag.attribute().isEmpty()) { - node.addNode(section.name()) - .addAttribute(tag.attribute(), field.getValue()); - } else { - node.addValueNode(section.name(), field.getValue()); - } - } - -} diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlNode.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlNode.java similarity index 98% rename from xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlNode.java rename to xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlNode.java index d7c11dc..81967e3 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlNode.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlNode.java @@ -1,11 +1,11 @@ -package io.jonasg.xjx.serdes.seraialize; - -import io.jonasg.xjx.Attributes; +package io.jonasg.xjx.serdes.serialize; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import io.jonasg.xjx.Attributes; + public final class XmlNode { private final String name; private Object value; diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlNodeStructureFactory.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlNodeStructureFactory.java new file mode 100644 index 0000000..f98f645 --- /dev/null +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlNodeStructureFactory.java @@ -0,0 +1,76 @@ +package io.jonasg.xjx.serdes.serialize; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.util.List; + +import io.jonasg.xjx.serdes.Path; +import io.jonasg.xjx.serdes.Section; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.reflector.InstanceField; +import io.jonasg.xjx.serdes.reflector.Reflector; + +public class XmlNodeStructureFactory { + + public static final List> BASIC_TYPES = List.of( + String.class, Integer.class, Boolean.class, boolean.class, Long.class, long.class, BigDecimal.class, Double.class, + double.class, char.class, Character.class, LocalDate.class, LocalDateTime.class, ZonedDateTime.class, byte[].class); + + public XmlNode build(T data) { + return getXmlNode(Path.parse("/"), data, null); + } + + private XmlNode getXmlNode(Path parentPath, T data, XmlNode node) { + if (data != null && !BASIC_TYPES.contains(data.getClass()) && !data.getClass().isEnum()) { + List fields = Reflector.reflect(data).fields(); + node = buildNodeForFields(parentPath, node, fields); + } + return node; + } + + private XmlNode buildNodeForFields(Path parentPath, XmlNode node, List fields) { + for (InstanceField field : fields) { + if (field.hasAnnotation(Tag.class)) { + node = buildNodeForField(field, parentPath, node); + } + else if (!BASIC_TYPES.contains(field.type())) { + return buildNodeForFields(parentPath, node, field.reflect().fields()); + } + } + return node; + } + + private XmlNode buildNodeForField(InstanceField field, Path parentPath, XmlNode rootNode) { + var tag = field.getAnnotation(Tag.class); + var path = parentPath.append(Path.parse(tag.path())); + if (rootNode == null) { + rootNode = new XmlNode(path.getRoot()); + } + var node = rootNode; + for (int i = 1; i < path.size(); i++) { + Section section = path.getSection(i); + if (section.isLeaf()) { + handleLeafNode(field, section, tag, node); + } + else { + node = node.addNode(section.name()); + } + } + return getXmlNode(path, field.getValue(), rootNode); + } + + private void handleLeafNode(InstanceField field, Section section, Tag tag, XmlNode node) { + if (!tag.attribute().isEmpty()) { + if (field.getValue() != null) { + node.addNode(section.name()) + .addAttribute(tag.attribute(), field.getValue()); + } + } + else { + node.addValueNode(section.name(), field.getValue()); + } + } + +} diff --git a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlStringBuilder.java b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlStringBuilder.java similarity index 95% rename from xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlStringBuilder.java rename to xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlStringBuilder.java index e8e7d28..f02d547 100644 --- a/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/seraialize/XmlStringBuilder.java +++ b/xjx-serdes/src/main/java/io/jonasg/xjx/serdes/serialize/XmlStringBuilder.java @@ -1,6 +1,4 @@ -package io.jonasg.xjx.serdes.seraialize; - -import io.jonasg.xjx.serdes.seraialize.XmlNode; +package io.jonasg.xjx.serdes.serialize; import java.util.List; diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ComplexTypeDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ComplexTypeDeserializationTest.java index 1e1798c..0f5202d 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ComplexTypeDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ComplexTypeDeserializationTest.java @@ -1,10 +1,11 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; + public class ComplexTypeDeserializationTest { @Test void mapFieldsOnComplexType() { diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/CustomValueDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/CustomValueDeserializationTest.java index 2cb65d7..cd991ec 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/CustomValueDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/CustomValueDeserializationTest.java @@ -1,10 +1,11 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; + public class CustomValueDeserializationTest { @Test diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DataTypeDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DataTypeDeserializationTest.java index 83ac0a7..fdffe58 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DataTypeDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DataTypeDeserializationTest.java @@ -1,11 +1,7 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; -import org.assertj.core.api.ThrowableAssert; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import java.math.BigDecimal; import java.time.LocalDate; @@ -15,8 +11,13 @@ import java.util.Map; import java.util.Objects; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import org.assertj.core.api.ThrowableAssert; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; public class DataTypeDeserializationTest { diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationFieldAccessTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationFieldAccessTest.java index fe1c8f9..acd331d 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationFieldAccessTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationFieldAccessTest.java @@ -1,10 +1,11 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; + public class DeserializationFieldAccessTest { @Test diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationInstanceCreationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationInstanceCreationTest.java index 81c4cae..a778d26 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationInstanceCreationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/DeserializationInstanceCreationTest.java @@ -1,10 +1,11 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; + public class DeserializationInstanceCreationTest { @Test diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/EnumDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/EnumDeserializationTest.java index d4530d1..4886239 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/EnumDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/EnumDeserializationTest.java @@ -1,10 +1,11 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; + public class EnumDeserializationTest { diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/GeneralDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/GeneralDeserializationTest.java index 0ec0770..38f0750 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/GeneralDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/GeneralDeserializationTest.java @@ -1,12 +1,13 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + import org.assertj.core.api.ThrowableAssert; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; public class GeneralDeserializationTest { diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ListDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ListDeserializationTest.java index 7118cc7..c70191a 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ListDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/ListDeserializationTest.java @@ -1,15 +1,16 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; -import org.assertj.core.api.ThrowableAssert; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.LocalDate; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import org.assertj.core.api.ThrowableAssert; +import org.junit.jupiter.api.Test; + +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; public class ListDeserializationTest { diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/SetDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/SetDeserializationTest.java index f267170..f2d5fec 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/SetDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/SetDeserializationTest.java @@ -1,15 +1,16 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; -import org.assertj.core.api.Assertions; -import org.assertj.core.api.ThrowableAssert; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import java.util.Objects; import java.util.Set; -import static org.assertj.core.api.Assertions.assertThat; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.ThrowableAssert; +import org.junit.jupiter.api.Test; + +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; public class SetDeserializationTest { diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/TagAttributeDeserializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/TagAttributeDeserializationTest.java index 56dc70a..a7a3dac 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/TagAttributeDeserializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/deserialize/TagAttributeDeserializationTest.java @@ -1,13 +1,14 @@ package io.jonasg.xjx.serdes.deserialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; +import java.math.BigDecimal; + import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.math.BigDecimal; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; public class TagAttributeDeserializationTest { @Test diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/EnumSerializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/EnumSerializationTest.java index db169a0..0db8348 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/EnumSerializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/EnumSerializationTest.java @@ -1,13 +1,13 @@ package io.jonasg.xjx.serdes.serialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -public class EnumSerializationTest { +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; +public class EnumSerializationTest { @Test void mapToFieldOfTypeEnum_whenCharacterDataMatchesEnumConstantName() { diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/GeneralSerializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/GeneralSerializationTest.java index 4476378..5531018 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/GeneralSerializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/GeneralSerializationTest.java @@ -1,100 +1,257 @@ package io.jonasg.xjx.serdes.serialize; +import java.util.stream.Stream; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import io.jonasg.xjx.serdes.Tag; import io.jonasg.xjx.serdes.XjxSerdes; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; public class GeneralSerializationTest { - @Test - void serializeNestedTags() { - // given - var weatherData = new WeatherData("USA", "New York"); - // when - String xml = new XjxSerdes().write(weatherData); + static Stream serializeNestedTags() { + class WeatherDataPojo { - // then - Assertions.assertThat(xml).isEqualTo(""" - - - USA - - New York - - - - """); - } + @Tag(path = "/WeatherData/Location/Country") + private final String country; + + @Tag(path = "/WeatherData/Location/City/Name") + private final String city; + + @Tag(path = "/WeatherData/Location/City/Name", attribute = "code") + private final String code; + + public WeatherDataPojo(String country, String city, String code) { + this.country = country; + this.city = city; + this.code = code; + } + } + record WeatherDataRecord( + @Tag(path = "/WeatherData/Location/Country") + String country, + @Tag(path = "/WeatherData/Location/City/Name") + String city, + @Tag(path = "/WeatherData/Location/City/Name", attribute = "code") + String postalCode + ) {} + return Stream.of( + Arguments.of(new WeatherDataPojo("USA", "New York", "NY")), + Arguments.of(new WeatherDataRecord("USA", "New York", "NY")) + ); + } + + @ParameterizedTest + @MethodSource("serializeNestedTags") + void serializeNestedTags(Object data) { + // when + String xml = new XjxSerdes().write(data); + + // then + Assertions.assertThat(xml).isEqualTo(""" + + + USA + + New York + + + + """); + } + + static Stream serializeNestedObjectsWithoutTagAnnotation() { + class Code { + @Tag(path = "/WeatherData/Location/Country", attribute = "code") + private final String value; + Code(String value) { this.value = value; } + } + class Country { + @Tag(path = "/WeatherData/Location/Country") + private final String name; + private final Code code; + Country(String name, Code code) { this.name = name; this.code = code; } + } + class WeatherData { + private final Country country; + WeatherData(Country country) { this.country = country; } + } + + record CodeRecord(@Tag(path = "/WeatherData/Location/Country", attribute = "code") String value) {} + record CountryRecord(@Tag(path = "/WeatherData/Location/Country") String name, CodeRecord code) {} + record WeatherDataRecord(CountryRecord country) {} + + return Stream.of( + Arguments.of(new WeatherData(new Country("United States of America", new Code("US")))), + Arguments.of(new WeatherDataRecord(new CountryRecord("United States of America", new CodeRecord("US")))) + ); + } + + @ParameterizedTest + @MethodSource("serializeNestedObjectsWithoutTagAnnotation") + void serializeNestedObjectsWithoutTagAnnotation(Object data) { + // when + String xml = new XjxSerdes().write(data); + + // then + Assertions.assertThat(xml).isEqualTo(""" + + + United States of America + + + """); + } + + static Stream serializeNullFieldsToSelfClosingTag() { + class WeatherData { + @Tag(path = "/WeatherData/Location/Country") + private final String country; + @Tag(path = "/WeatherData/Location/City/Name") + private final String city; + WeatherData(String country, String city) { this.country = country; this.city = city; } + } + record WeatherDataRecord(@Tag(path = "/WeatherData/Location/Country") String country, + @Tag(path = "/WeatherData/Location/City/Name") String city) {} - @Test - void serializeNullFieldsToSelfClosingTag() { - // given - var weatherData = new WeatherData(null, "New York"); + return Stream.of( + Arguments.of(new WeatherData(null, "New York")), + Arguments.of(new WeatherDataRecord(null, "New York")) + ); + } - // when - String xml = new XjxSerdes().write(weatherData); + @ParameterizedTest + @MethodSource("serializeNullFieldsToSelfClosingTag") + void serializeNullFieldsToSelfClosingTag(Object data) { - // then - Assertions.assertThat(xml).isEqualTo(""" + // when + String xml = new XjxSerdes().write(data); + + // then + Assertions.assertThat(xml).isEqualTo(""" + + + + + New York + + + + """); + } + + static Stream serializeNullFieldsMappedToAnAttribute_byNotAddingAttributeToTag_ofAnAlreadyExistingTag() { + class WeatherData { + @Tag(path = "/WeatherData/Location/Country") + private final String country; + @Tag(path = "/WeatherData/Location/City/Name") + private final String city; + @Tag(path = "/WeatherData/Location/City/Name", attribute = "code") + private final String code; + WeatherData(String country, String city, String code) { this.country = country; this.city = city; this.code = code; } + } + record WeatherDataRecord(@Tag(path = "/WeatherData/Location/Country") String country, + @Tag(path = "/WeatherData/Location/City/Name") String city, + @Tag(path = "/WeatherData/Location/City/Name", attribute = "code") String code) {} + + return Stream.of( + Arguments.of(new WeatherData(null, "New York", null)), + Arguments.of(new WeatherDataRecord(null, "New York", null)) + ); + } + + @ParameterizedTest + @MethodSource("serializeNullFieldsMappedToAnAttribute_byNotAddingAttributeToTag_ofAnAlreadyExistingTag") + void serializeNullFieldsMappedToAnAttribute_byNotAddingAttributeToTag_ofAnAlreadyExistingTag(Object data) { + // when + String xml = new XjxSerdes().write(data); + + // then + Assertions.assertThat(xml).isEqualTo(""" + + + + + New York + + + + """); + } + + static Stream serializeNullFieldsMappedToAnAttribute_byNotAddingAttributeToTag_ofATagThatIsNotMapped() { + class WeatherData { + @Tag(path = "/WeatherData/Location/Country") + private final String country; + @Tag(path = "/WeatherData/Location/City/Name", attribute = "code") + private final String code; + WeatherData(String country, String code) { this.country = country; this.code = code; } + } + record WeatherDataRecord(@Tag(path = "/WeatherData/Location/Country") String country, + @Tag(path = "/WeatherData/Location/City/Name", attribute = "code") String code) {} + + return Stream.of( + Arguments.of(new WeatherData(null, null)), + Arguments.of(new WeatherDataRecord(null, null)) + ); + } + + @ParameterizedTest + @MethodSource("serializeNullFieldsMappedToAnAttribute_byNotAddingAttributeToTag_ofATagThatIsNotMapped") + void serializeNullFieldsMappedToAnAttribute_byNotAddingAttributeToTag_ofATagThatIsNotMapped(Object data) { + // when + String xml = new XjxSerdes().write(data); + + // then + Assertions.assertThat(xml).isEqualTo(""" - - New York - + """); - } + } + + static Stream serializeNullFieldsToSelfClosingTagContainingNonNullAttribute() { + class WeatherDataWithAttribute { + @Tag(path = "/WeatherData/Location/Country") + private final String country; + @Tag(path = "/WeatherData/Location/Country", attribute = "code") + private final String code; + public WeatherDataWithAttribute(String country, String code) { + this.country = country; + this.code = code; + } + } + record WeatherDataWithAttributeRecord( + @Tag(path = "/WeatherData/Location/Country") String country, + @Tag(path = "/WeatherData/Location/Country", attribute = "code") String code + ) {} - @Test - void serializeNullFieldsToSelfClosingTagContainingNonNullAttribute() { - // given - var weatherData = new WeatherDataWithAttribute(null, "USA"); + return Stream.of( + Arguments.of(new WeatherDataWithAttribute(null, "USA")), + Arguments.of(new WeatherDataWithAttributeRecord(null, "USA")) + ); + } - // when - String xml = new XjxSerdes().write(weatherData); + @ParameterizedTest + @MethodSource("serializeNullFieldsToSelfClosingTagContainingNonNullAttribute") + void serializeNullFieldsToSelfClosingTagContainingNonNullAttribute(Object data) { + // when + String xml = new XjxSerdes().write(data); - // then - Assertions.assertThat(xml).isEqualTo(""" + // then + Assertions.assertThat(xml).isEqualTo(""" """); - } - - @SuppressWarnings("unused") - static class WeatherData { - - @Tag(path = "/WeatherData/Location/Country") - private final String country; - - @Tag(path = "/WeatherData/Location/City/Name") - private final String city; - - public WeatherData(String country, String city) { - this.country = country; - this.city = city; - } - } - - - @SuppressWarnings("unused") - static class WeatherDataWithAttribute { - - @Tag(path = "/WeatherData/Location/Country") - private final String country; - - @Tag(path = "/WeatherData/Location/Country", attribute = "code") - private final String code; - - public WeatherDataWithAttribute(String country, String code) { - this.country = country; - this.code = code; - } - } + } } diff --git a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/TagAttributeSerializationTest.java b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/TagAttributeSerializationTest.java index 35051cb..38d0b06 100644 --- a/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/TagAttributeSerializationTest.java +++ b/xjx-serdes/src/test/java/io/jonasg/xjx/serdes/serialize/TagAttributeSerializationTest.java @@ -1,11 +1,12 @@ package io.jonasg.xjx.serdes.serialize; -import io.jonasg.xjx.serdes.Tag; -import io.jonasg.xjx.serdes.XjxSerdes; +import java.math.BigDecimal; + import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import java.math.BigDecimal; +import io.jonasg.xjx.serdes.Tag; +import io.jonasg.xjx.serdes.XjxSerdes; public class TagAttributeSerializationTest {