Skip to content

Commit fe6b1db

Browse files
committed
Merge remote-tracking branch 'upstream/main' into interface-adapter
2 parents 5f8a759 + eba8bd1 commit fe6b1db

File tree

26 files changed

+363
-84
lines changed

26 files changed

+363
-84
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
fail-fast: false
1414
matrix:
15-
java_version: [19]
15+
java_version: [19,20]
1616
os: [ubuntu-latest]
1717

1818
steps:

blackbox-test/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>io.avaje</groupId>
66
<artifactId>avaje-jsonb-parent</artifactId>
7-
<version>1.5-SNAPSHOT</version>
7+
<version>1.5-RC1</version>
88
</parent>
99

1010
<artifactId>blackbox-test</artifactId>
@@ -28,7 +28,7 @@
2828
<dependency>
2929
<groupId>io.avaje</groupId>
3030
<artifactId>avaje-jsonb</artifactId>
31-
<version>1.5-SNAPSHOT</version>
31+
<version>1.5-RC1</version>
3232
</dependency>
3333

3434
<!-- <dependency>-->
@@ -40,7 +40,7 @@
4040
<dependency>
4141
<groupId>io.avaje</groupId>
4242
<artifactId>avaje-jsonb-generator</artifactId>
43-
<version>1.5-SNAPSHOT</version>
43+
<version>1.5-RC1</version>
4444
<scope>provided</scope>
4545
</dependency>
4646

jsonb-generator/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
<parent>
55
<groupId>io.avaje</groupId>
66
<artifactId>avaje-jsonb-parent</artifactId>
7-
<version>1.5-SNAPSHOT</version>
7+
<version>1.5-RC1</version>
88
</parent>
99

1010
<artifactId>avaje-jsonb-generator</artifactId>
1111
<name>jsonb generator</name>
1212
<description>annotation processor generating json adapters</description>
1313
<properties>
14-
<avaje.prisms.version>1.6</avaje.prisms.version>
14+
<avaje.prisms.version>1.8</avaje.prisms.version>
1515
</properties>
1616

1717
<dependencies>

jsonb-generator/src/main/java/io/avaje/jsonb/generator/ClassReader.java

Lines changed: 104 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package io.avaje.jsonb.generator;
22

33
import static io.avaje.jsonb.generator.ProcessingContext.jdkVersion;
4+
import static io.avaje.jsonb.generator.ProcessingContext.previewEnabled;
45
import static io.avaje.jsonb.generator.ProcessingContext.useEnhancedSwitch;
6+
import static java.util.stream.Collectors.toList;
57

68
import java.lang.reflect.InvocationTargetException;
7-
import java.util.HashSet;
8-
import java.util.List;
9-
import java.util.Objects;
10-
import java.util.Set;
11-
import java.util.TreeSet;
9+
import java.util.*;
1210

1311
import javax.lang.model.element.Element;
1412
import javax.lang.model.element.ElementKind;
@@ -34,8 +32,10 @@ final class ClassReader implements BeanReader {
3432
private final boolean isRecord;
3533
private final boolean usesTypeProperty;
3634
private final boolean useEnum;
37-
private final boolean useInstanceofPattern = jdkVersion() >= 17;
38-
private final boolean nullSwitch = jdkVersion() >= 21;
35+
private static final boolean useInstanceofPattern = jdkVersion() >= 17;
36+
private static final boolean nullSwitch = jdkVersion() >= 21 || (jdkVersion() >= 17 && previewEnabled());
37+
private final Map<String, Integer> frequencyMap = new HashMap<>();
38+
private final Map<String, Boolean> isCommonFieldMap = new HashMap<>();
3939

4040
ClassReader(TypeElement beanType) {
4141
this(beanType, null);
@@ -66,7 +66,6 @@ final class ClassReader implements BeanReader {
6666
.map(FieldReader::type)
6767
.map(GenericType::topType)
6868
.map(ProcessingContext::element)
69-
.filter(Objects::nonNull)
7069
.filter(e -> e.getKind() == ElementKind.ENUM)
7170
.isPresent();
7271
}
@@ -200,6 +199,13 @@ public void writeConstructor(Append writer) {
200199
final Set<String> uniqueTypes = new HashSet<>();
201200
for (final FieldReader allField : allFields) {
202201
if (allField.include() && !allField.isRaw() && uniqueTypes.add(allField.adapterShortType())) {
202+
if (hasSubTypes) {
203+
final var isCommonDiffType =
204+
allFields.stream()
205+
.filter(s -> s.fieldName().equals(allField.fieldName()))
206+
.anyMatch(f -> !allField.adapterShortType().equals(f.adapterShortType()));
207+
isCommonFieldMap.put(allField.fieldName(), isCommonDiffType);
208+
}
203209
allField.writeConstructor(writer);
204210
}
205211
}
@@ -208,8 +214,14 @@ public void writeConstructor(Append writer) {
208214
writer.append("\"").append(typeProperty).append("\", ");
209215
}
210216
final StringBuilder builder = new StringBuilder();
217+
218+
//set to prevent writing same key twice
219+
final var seen = new HashSet<String>();
211220
for (int i = 0, size = allFields.size(); i < size; i++) {
212221
final FieldReader fieldReader = allFields.get(i);
222+
if (!seen.add(fieldReader.fieldName())) {
223+
continue;
224+
}
213225
if (i > 0) {
214226
builder.append(", ");
215227
}
@@ -358,11 +370,16 @@ private void writeJsonBuildResult(Append writer, String varName) {
358370
if (i > 0) {
359371
writer.append(", ");
360372
}
361-
writer.append(constructorParamName(params.get(i).name())); // assuming name matches field here?
373+
final var name = params.get(i).name();
374+
// append increasing numbers to constructor params sharing names with other subtypes
375+
final var frequency = frequencyMap.compute(name, (k, v) -> v == null ? 0 : v + 1);
376+
// assuming name matches field here?
377+
writer.append(constructorParamName(name + (frequency == 0 ? "" : frequency.toString())));
362378
}
363379
writer.append(");").eol();
364380
for (final FieldReader allField : allFields) {
365381
if (allField.includeFromJson()) {
382+
frequencyMap.compute(allField.fieldName(), (k, v) -> v == null ? 0 : v + 1);
366383
allField.writeFromJsonSetter(writer, varName, "");
367384
}
368385
}
@@ -387,10 +404,12 @@ private void writeFromJsonWithSubTypes(Append writer) {
387404
writer.append(" case null -> ").append("throw new IllegalStateException(\"Missing Required %s property that determines deserialization type\");", typeProperty).eol();
388405
}
389406
}
407+
// another frequency map to append numbers to the subtype constructor params
408+
final Map<String, Integer> frequencyMap2 = new HashMap<>();
390409

391410
for (final TypeSubTypeMeta subTypeMeta : typeReader.subTypes()) {
392411
final var varName = Util.initLower(Util.shortName(subTypeMeta.type()));
393-
subTypeMeta.writeFromJsonBuild(writer, typeVar, varName, this, useSwitch, useEnum);
412+
subTypeMeta.writeFromJsonBuild(writer, typeVar, varName, this, useSwitch, useEnum, frequencyMap2, isCommonFieldMap);
394413
}
395414
if (useSwitch) {
396415
writer.append(" default").appendSwitchCase().eol().append(" ");
@@ -431,8 +450,38 @@ private void writeFromJsonSwitch(Append writer, boolean defaultConstructor, Stri
431450
writer.append(" type = stringJsonAdapter.fromJson(reader);").eol();
432451
writer.append(" break;").eol();
433452
}
453+
// don't write same switch case twice
454+
final var seen = new HashSet<>();
434455
for (final FieldReader allField : allFields) {
435-
allField.writeFromJsonSwitch(writer, defaultConstructor, varName, caseInsensitiveKeys);
456+
final var name = allField.fieldName();
457+
if (!seen.add(name)) {
458+
continue;
459+
}
460+
if (hasSubTypes) {
461+
final var isCommonFieldDiffType = isCommonFieldMap.get(name);
462+
if (isCommonFieldDiffType == null || !isCommonFieldDiffType) {
463+
allField.writeFromJsonSwitch(
464+
writer,
465+
defaultConstructor,
466+
varName,
467+
caseInsensitiveKeys,
468+
allFields.stream()
469+
.filter(x -> x.fieldName().equals(name))
470+
.flatMap(f -> f.getAliases().stream())
471+
.collect(toList()));
472+
} else {
473+
// if subclass shares a field name with another subclass
474+
// write a special case statement
475+
writeSubTypeCase(
476+
name,
477+
writer,
478+
allFields.stream().filter(x -> x.fieldName().equals(name)).collect(toList()),
479+
defaultConstructor,
480+
varName);
481+
}
482+
483+
} else
484+
allField.writeFromJsonSwitch(writer, defaultConstructor, varName, caseInsensitiveKeys, List.of());
436485
}
437486
writer.append(" default:").eol();
438487
final String unmappedFieldName = caseInsensitiveKeys ? "origFieldName" : "fieldName";
@@ -448,6 +497,50 @@ private void writeFromJsonSwitch(Append writer, boolean defaultConstructor, Stri
448497
writer.append(" reader.endObject();").eol();
449498
}
450499

500+
private void writeSubTypeCase(String name, Append writer, List<FieldReader> commonFields, boolean defaultConstructor, String varName) {
501+
writer.append(" case \"%s\":", name).eol();
502+
// get all possible aliases of this field from the subtypes
503+
for (final String alias :
504+
commonFields.stream().map(FieldReader::getAliases).findFirst().orElseGet(List::of)) {
505+
final String propertyKey = caseInsensitiveKeys ? alias.toLowerCase() : alias;
506+
writer.append(" case \"%s\":", propertyKey).eol();
507+
}
508+
var elseIf = false;
509+
// write the case statements with subtypeCheck
510+
for (final FieldReader fieldReader : commonFields) {
511+
final var subtype = new ArrayList<>(fieldReader.getSubTypes().values()).get(0);
512+
final var setter = fieldReader.getSetter();
513+
final var adapterFieldName = fieldReader.getAdapterFieldName();
514+
final var fieldName = fieldReader.getFieldNameWithNum();
515+
if (useEnum) {
516+
writer.append(" %sif (%s.equals(%s)) {", elseIf ? "else " : "", subtype.name(), "type").eol();
517+
} else {
518+
writer.append(" %sif (\"%s\".equals(%s)) {", elseIf ? "else " : "", subtype.name(), "type").eol();
519+
}
520+
elseIf = true;
521+
if (!fieldReader.isDeserialize()) {
522+
writer.append(" reader.skipValue();");
523+
} else if (defaultConstructor) {
524+
if (setter != null) {
525+
writer.append(" _$%s.%s(%s.fromJson(reader));", varName, setter.getName(), adapterFieldName);
526+
} else if (fieldReader.isPublicField()) {
527+
writer.append(" _$%s.%s = %s.fromJson(reader);", varName, fieldName, adapterFieldName);
528+
}
529+
} else {
530+
writer.append(" _val$%s = %s.fromJson(reader);", fieldName, adapterFieldName);
531+
if (!fieldReader.isConstructorParam()) {
532+
writer.eol().append(" _set$%s = true;", fieldName);
533+
}
534+
}
535+
writer.eol().append(" }").eol();
536+
}
537+
writer
538+
.append(" else {").eol()
539+
.append(" throw new IllegalStateException(\"Missing Required type3 property that determines deserialization type\");").eol()
540+
.append(" }").eol()
541+
.append(" break;").eol().eol();
542+
}
543+
451544
private String typePropertyKey() {
452545
return caseInsensitiveKeys ? typeProperty.toLowerCase() : typeProperty;
453546
}

0 commit comments

Comments
 (0)