Skip to content

Commit

Permalink
fix: allow tag containing repeated elements to be mapped to multiple …
Browse files Browse the repository at this point in the history
…collection types

A tag containing multiple repeated different tags can now be mapped to multiple different
collection types.

<a>
  <b/>
  <c/>
  <b/>
  <c/>
</a>

can be mapped to two fields

@tag(path = "/a", items = "b")
List<B> bs;

@tag(path = "/a", items = "c")
List<B> cs;
  • Loading branch information
jonas-grgt committed Mar 14, 2024
1 parent 2bc0333 commit 8c8eee9
Show file tree
Hide file tree
Showing 8 changed files with 789 additions and 79 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,43 @@ Example XML document:
</WeatherData>
```
### Map mixed tags within a container to multiple collections
Xjx is able to map repeated mixed tags within a container or
at the root tag to multiple collections.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<WeatherReport>
<Locations>
<City name="A"/>
<Town name="B"/>
<Town name="D"/>
<Town name="E"/>
<City name="F"/>
<City name="H"/>
<Town name="C"/>
<City name="G"/>
</Locations>
</WeatherReport>
```
```java
class WeatherReport {
@Tag(path = "/WeatherReport/Locations", items = "Town")
List<Town> towns;
@Tag(path = "/WeatherReport/Locations", items = "City")
List<City> cities;
}
class Town {
@Tag(path = "/WeatherReport/Locations/Town", attribute = "name")
String name;
}
```
### Map types
Maps can be deserialized either as a field or a top-level type. Consider the following XML document:
Expand Down
20 changes: 12 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,32 @@

<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven-deploy-plugin.version>3.0.0</maven-deploy-plugin.version>
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
<surefire-maven-plugin.version>3.1.2</surefire-maven-plugin.version>
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>

<flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
<surefire-maven-plugin.version>3.1.2</surefire-maven-plugin.version>
<maven-deploy-plugin.version>3.0.0</maven-deploy-plugin.version>
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<jreleaser.version>1.9.0</jreleaser.version>
<junit-bom.version>5.10.1</junit-bom.version>
<assertj-core.version>3.23.1</assertj-core.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.10.1</version>
<version>${junit-bom.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.23.1</version>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down Expand Up @@ -212,6 +215,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.jonasg.xjx.serdes.deserialize;

import java.util.function.Supplier;

public class LazySupplier<T> implements Supplier<T> {
private T instance;
private Supplier<T> initializer;

public LazySupplier(Supplier<T> initializer) {
this.initializer = initializer;
}

@Override
public T get() {
if (instance == null) {
instance = initializer.get();
}
return instance;
}

public void reset(Supplier<T> supplier) {
this.instance = null;
this.initializer = supplier;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

public class PathBasedSaxHandler<T> implements SaxHandler {

private final Function<String, Map<Path, PathWriter>> indexSupplier;
private final Function<String, PathWriterIndex> indexSupplier;

private final XjxConfiguration configuration;

Expand All @@ -23,20 +23,20 @@ public class PathBasedSaxHandler<T> implements SaxHandler {

private Path path;

private Map<Path, PathWriter> pathWriterIndex;
private PathWriterIndex pathWriterIndex;

private String data;

private SaxHandler mapRootSaxHandlerDelegate;

private String mapStartTag;

public PathBasedSaxHandler(Function<String, Map<Path, PathWriter>> indexSupplier, XjxConfiguration configuration) {
public PathBasedSaxHandler(Function<String, PathWriterIndex> indexSupplier, XjxConfiguration configuration) {
this.indexSupplier = indexSupplier;
this.configuration = configuration;
}

public PathBasedSaxHandler(Function<String, Map<Path, PathWriter>> indexSupplier, String rootTag, XjxConfiguration configuration) {
public PathBasedSaxHandler(Function<String, PathWriterIndex> indexSupplier, String rootTag, XjxConfiguration configuration) {
this.indexSupplier = indexSupplier;
this.rootTag = rootTag;
this.configuration = configuration;
Expand All @@ -57,24 +57,26 @@ public void startTag(String namespace, String name, List<Attribute> attributes)
handleRootTag(name);
} else {
this.path = path.append(name);
var pathWriter = pathWriterIndex.get(path);
if (pathWriter != null) {
if (pathWriter.getObjectInitializer() != null) {
Object object = pathWriter.getObjectInitializer().get();
if (object instanceof Map) {
this.mapRootSaxHandlerDelegate = new MapRootSaxHandler((HashMap<String, Object>) object);
this.mapStartTag = name;
} else if (object instanceof MapWithTypeInfo mapWithTypeInfo) {
this.mapRootSaxHandlerDelegate = new TypedValueMapSaxHandler(mapWithTypeInfo, configuration);
this.mapStartTag = name;
}
this.objectInstances.push(object);
}
List<PathWriter> pathWriters = pathWriterIndex.get(path);
if (pathWriters != null) {
pathWriters.forEach(pathWriter -> {
if (pathWriter.getObjectInitializer() != null) {
Object object = pathWriter.getObjectInitializer().get();
if (object instanceof Map) {
this.mapRootSaxHandlerDelegate = new MapRootSaxHandler((HashMap<String, Object>) object);
this.mapStartTag = name;
} else if (object instanceof MapWithTypeInfo mapWithTypeInfo) {
this.mapRootSaxHandlerDelegate = new TypedValueMapSaxHandler(mapWithTypeInfo, configuration);
this.mapStartTag = name;
}
this.objectInstances.push(object);
}
});
}
attributes.forEach(a -> {
var attributeWriter = pathWriterIndex.get(path.appendAttribute(a.name()));
if (attributeWriter != null) {
attributeWriter.getValueInitializer().accept(a.value());
List<PathWriter> attributeWriters = pathWriterIndex.get(path.appendAttribute(a.name()));
if (attributeWriters != null) {
attributeWriters.stream().forEach(attributeWriter -> attributeWriter.getValueInitializer().accept(a.value()));
}
});
}
Expand All @@ -89,17 +91,19 @@ public void endTag(String namespace, String name) {
this.mapRootSaxHandlerDelegate.endTag(namespace, name);
}
}
PathWriter pathWriter = pathWriterIndex.get(path);
if (pathWriter != null) {
if (data != null) {
pathWriter.getValueInitializer().accept(data);
}
if (pathWriter.getObjectInitializer() != null && !objectInstances.isEmpty() && objectInstances.size() != 1) {
if (pathWriter.getValueInitializer() != null) {
pathWriter.getValueInitializer().accept(objectInstances.peek());
List<PathWriter> pathWriters = pathWriterIndex.get(path);
if (pathWriters != null) {
pathWriters.forEach(pathWriter -> {
if (data != null) {
pathWriter.getValueInitializer().accept(data);
}
objectInstances.pop();
}
if (pathWriter.getObjectInitializer() != null && !objectInstances.isEmpty() && objectInstances.size() != 1) {
if (pathWriter.getValueInitializer() != null) {
pathWriter.getValueInitializer().accept(objectInstances.peek());
}
objectInstances.pop();
}
});
}
data = null;
path = path.pop();
Expand All @@ -117,15 +121,17 @@ private void handleRootTag(String name) {
this.pathWriterIndex = indexSupplier.apply(name);
this.rootTag = name;
path = Path.of(name);
PathWriter pathWriter = pathWriterIndex.get(path);
if (pathWriter != null) {
Object parent = pathWriter.getRootInitializer().get();
if (parent instanceof MapAsRoot mapAsRoot) {
this.mapRootSaxHandlerDelegate = new MapRootSaxHandler(mapAsRoot.map());
this.objectInstances.push(mapAsRoot.root());
} else {
this.objectInstances.push(parent);
}
List<PathWriter> pathWriters = pathWriterIndex.get(path);
if (pathWriters != null) {
pathWriters.forEach(pathWriter -> {
Object parent = pathWriter.getRootInitializer().get();
if (parent instanceof MapAsRoot mapAsRoot) {
this.mapRootSaxHandlerDelegate = new MapRootSaxHandler(mapAsRoot.map());
this.objectInstances.push(mapAsRoot.root());
} else {
this.objectInstances.push(parent);
}
});
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.jonasg.xjx.serdes.deserialize;

import io.jonasg.xjx.serdes.Path;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PathWriterIndex {

private final Map<Path, List<PathWriter>> index = new HashMap<>();

public void put(Path path, PathWriter pathWriter) {
index.compute(path, (p, w) -> {
if (w == null) {
List<PathWriter> pathWriters = new ArrayList<>();
pathWriters.add(pathWriter);
return pathWriters;
}
w.add(pathWriter);
return w;
});
}

public void putAll(PathWriterIndex pathWriterIndex) {
index.putAll(pathWriterIndex.index);
}

public List<PathWriter> get(Path path) {
return index.get(path);
}
}
Loading

0 comments on commit 8c8eee9

Please sign in to comment.