Skip to content

Commit 0a47c29

Browse files
committed
Support multiple child types #1
1 parent 910cb4e commit 0a47c29

File tree

4 files changed

+41
-21
lines changed

4 files changed

+41
-21
lines changed

processor/src/main/java/de/bethibande/serial/processor/generator/FieldInfo.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313
import javax.lang.model.element.TypeElement;
1414
import javax.lang.model.element.VariableElement;
1515
import javax.lang.model.type.TypeMirror;
16-
import java.util.HashMap;
17-
import java.util.Map;
18-
import java.util.Optional;
16+
import java.util.*;
1917

2018
@Builder(toBuilder = true)
2119
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@@ -33,8 +31,7 @@ public class FieldInfo implements HasAttributes {
3331
private AttributeMap attributes;
3432

3533
@Getter
36-
@Setter
37-
private FieldInfo child;
34+
private List<FieldInfo> children;
3835
@Getter
3936
@Setter
4037
private FieldInfo parent;
@@ -67,6 +64,15 @@ public FieldInfo(final TypeElement clazz, final VariableElement field, final Str
6764
this.attributes = new AttributeMap();
6865
this.nullable = false;
6966
this.generatedMethods = new HashMap<>();
67+
this.children = new ArrayList<>();
68+
}
69+
70+
public FieldInfo getFirstChild() {
71+
return children.getFirst();
72+
}
73+
74+
public void addChild(final FieldInfo child) {
75+
children.add(child);
7076
}
7177

7278
public TypeElement getTypeElement() {

processor/src/main/java/de/bethibande/serial/processor/serializer/EmbeddedTypeTransformer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import de.bethibande.serial.processor.generator.FieldInfo;
44

5+
import java.util.ArrayList;
56
import java.util.HashMap;
67

78
public abstract class EmbeddedTypeTransformer implements FieldBasedObjectTransformer {
@@ -17,16 +18,17 @@ public boolean isApplicable(final FieldInfo field, final ElementSerializer seria
1718
final FieldInfo child = createChildType(field, serializer)
1819
.toBuilder()
1920
.generatedMethods(new HashMap<>()) // Avoid sharing the same map instance with the parent
21+
.children(new ArrayList<>()) // Avoid sharing the same list instance with the parent
2022
.build();
2123
child.setTransformer(serializer.getFieldTransformer(child).orElseThrow());
2224
child.setParent(field);
23-
field.setChild(child);
25+
field.addChild(child);
2426

2527
return true;
2628
}
2729

2830
public String embeddedMethodName(final FieldInfo field) {
29-
return methodName(field.getChild());
31+
return methodName(field.getChildren().getFirst());
3032
}
3133

3234
}

processor/src/main/java/de/bethibande/serial/processor/serializer/FieldBasedObjectTransformer.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
import javax.lang.model.AnnotatedConstruct;
1313
import javax.lang.model.element.*;
1414
import javax.lang.model.type.TypeMirror;
15-
import java.util.ArrayList;
16-
import java.util.List;
17-
import java.util.Optional;
15+
import java.util.*;
1816
import java.util.function.Consumer;
1917
import java.util.function.Function;
2018

@@ -45,29 +43,43 @@ default Optional<String> wrappedMethodNameSuffix() {
4543
return Optional.empty();
4644
}
4745

46+
default void forEachSingleChild(final FieldInfo root,
47+
final Function<FieldInfo, FieldInfo> childFunction,
48+
final Consumer<FieldInfo> consumer) {
49+
forEach(root, field -> {
50+
final FieldInfo child = childFunction.apply(field);
51+
if (child == null) return Collections.emptyList();
52+
return Collections.singletonList(child);
53+
}, consumer);
54+
}
55+
4856
default void forEach(final FieldInfo root,
49-
final Function<FieldInfo, FieldInfo> nextFunction,
57+
final Function<FieldInfo, Collection<FieldInfo>> childFunction,
5058
final Consumer<FieldInfo> consumer) {
51-
FieldInfo current = root;
52-
while (current != null) {
59+
final Stack<FieldInfo> stack = new Stack<>();
60+
stack.push(root);
61+
while (!stack.isEmpty()) {
62+
final FieldInfo current = stack.pop();
63+
if (current == null) continue;
64+
5365
consumer.accept(current);
54-
current = nextFunction.apply(current);
66+
childFunction.apply(current).forEach(stack::push);
5567
}
5668
}
5769

5870
default <T> List<T> mapEach(final FieldInfo root,
59-
final Function<FieldInfo, FieldInfo> nextFunction,
60-
final Function<FieldInfo, T> consumer) {
71+
final Function<FieldInfo, Collection<FieldInfo>> childFunction,
72+
final Function<FieldInfo, T> consumer) {
6173
final List<T> values = new ArrayList<>();
62-
forEach(root, nextFunction, (current) -> values.add(consumer.apply(current)));
74+
forEach(root, childFunction, (current) -> values.add(consumer.apply(current)));
6375

6476
return values;
6577
}
6678

6779
default String methodName(final FieldInfo field) {
6880
final StringBuilder builder = new StringBuilder(field.getFieldName());
6981
if (field.getParent() != null) {
70-
forEach(
82+
forEachSingleChild(
7183
field.getParent(),
7284
FieldInfo::getParent,
7385
parent -> parent.getTransformer()
@@ -112,7 +124,7 @@ default void transformType(final TypeSpec.Builder builder,
112124
final SerializationContext ctx) {
113125
final List<MethodSpec> methods = mapEach(
114126
field,
115-
FieldInfo::getChild,
127+
FieldInfo::getChildren,
116128
child -> {
117129
final FieldBasedObjectTransformer transformer = child.getTransformer();
118130
final MethodSpec method = switch (methodType) {

processor/src/main/java/de/bethibande/serial/processor/serializer/types/ArrayTypes.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public Optional<String> wrappedMethodNameSuffix() {
4545
public CodeBlock createSerializationCode(final FieldInfo field, final SerializationContext ctx) {
4646
return CodeBlock.builder()
4747
.addStatement("$L.writeInt($L.length)", "writer", "value")
48-
.beginControlFlow("for ($T item : $L)", field.getChild().getType(), "value")
48+
.beginControlFlow("for ($T item : $L)", field.getFirstChild().getType(), "value")
4949
.addStatement("$L(item)", embeddedMethodName(field))
5050
.endControlFlow()
5151
.addStatement("return this")
@@ -55,7 +55,7 @@ public CodeBlock createSerializationCode(final FieldInfo field, final Serializat
5555
@Override
5656
public CodeBlock createDeserializationCode(final FieldInfo field, final SerializationContext ctx) {
5757
return CodeBlock.builder()
58-
.addStatement("final $T $L = new $T[$L.readInt()]", field.getType(), "value", field.getChild().getType(), "reader")
58+
.addStatement("final $T $L = new $T[$L.readInt()]", field.getType(), "value", field.getFirstChild().getType(), "reader")
5959
.beginControlFlow("for (int i = 0; i < $L.length; i++)", "value")
6060
.addStatement("$L[i] = $L()", "value", embeddedMethodName(field))
6161
.endControlFlow()

0 commit comments

Comments
 (0)