Skip to content

Commit 53ed43a

Browse files
SentryMandependabot[bot]rbygrave
authored
Expand @Value to Inline regular classes (#220)
* prism 1.6 * use enum switch * enhanced switch case * throw exception on duplicate enum value * skip iteration if static maps are filled * Update EnumReader.java * use configs * Update DefaultJsonbProvider.java * Update DefaultJsonbProvider.java * Update DefaultJsonbProvider.java * Revert "Update DefaultJsonbProvider.java" This reverts commit afdd3a8. * support java.util.Date People shouldn't use it, but the reality is that this is still used all over the place * C style for is faster * Bump io.helidon.webserver:helidon-webserver from 4.0.4 to 4.0.5 Bumps io.helidon.webserver:helidon-webserver from 4.0.4 to 4.0.5. --- updated-dependencies: - dependency-name: io.helidon.webserver:helidon-webserver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * start * fix tests * Update TypeReader.java * Bump io.avaje:junit from 1.3 to 1.4 Bumps io.avaje:junit from 1.3 to 1.4. --- updated-dependencies: - dependency-name: io.avaje:junit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Version 1.10 * Bump to next snapshot * Bump io.avaje:avaje-inject from 9.10 to 9.11 Bumps [io.avaje:avaje-inject](https://github.com/avaje/avaje-inject) from 9.10 to 9.11. - [Release notes](https://github.com/avaje/avaje-inject/releases) - [Commits](avaje/avaje-inject@9.10...9.11) --- updated-dependencies: - dependency-name: io.avaje:avaje-inject dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Bump org.springframework.boot:spring-boot-dependencies Bumps [org.springframework.boot:spring-boot-dependencies](https://github.com/spring-projects/spring-boot) from 3.2.2 to 3.2.3. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](spring-projects/spring-boot@v3.2.2...v3.2.3) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-dependencies dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * if not a double, get int value * Update BasicTypeAdapters.java * Update JsonWriteAdapter.java * Update Processor.java * move test package * add generator version * Revert "add generator version" This reverts commit 844b204. * Format only changes --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
1 parent 7149c9b commit 53ed43a

File tree

7 files changed

+302
-163
lines changed

7 files changed

+302
-163
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ build/
88
*.project
99
*.class
1010
.DS_Store
11+
jsonb-generator/.factorypath
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.example.customer.value;
2+
3+
import org.example.customer.Address;
4+
5+
import io.avaje.jsonb.Json;
6+
7+
@Json
8+
public record ValueInline(int a, Nested nested, Nested2 nested2, Nested3 nested3, Nested4 complex) {
9+
public record Nested(@Json.Value int nestA, String nestB) {
10+
public Nested(int nestA) {
11+
this(nestA, "idk");
12+
}
13+
}
14+
15+
public record Nested2(@Json.Value int nestb, String nestB) {
16+
17+
@Json.Creator
18+
public static Nested2 of(int nestB) {
19+
return new Nested2(nestB, "somethin");
20+
}
21+
}
22+
23+
public record Nested3(@Json.Value Nested2 nesting) {}
24+
25+
public static class Nested4 {
26+
private final Address address;
27+
28+
public Nested4(Address address) {
29+
this.address = address;
30+
}
31+
32+
@Json.Value
33+
public Address address() {
34+
return address;
35+
}
36+
}
37+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.example.customer.value;
2+
3+
import io.avaje.jsonb.Jsonb;
4+
import org.example.customer.Address;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
9+
class InlineTest {
10+
11+
Jsonb jsonb = Jsonb.builder().build();
12+
13+
@Test
14+
void toJsonFromJson() {
15+
16+
final var address = new Address((long) 123, "avenue");
17+
final var bean =
18+
new ValueInline(
19+
69,
20+
new ValueInline.Nested(2),
21+
new ValueInline.Nested2(3, "discarded"),
22+
new ValueInline.Nested3(new ValueInline.Nested2(2, "discarded")),
23+
new ValueInline.Nested4(address));
24+
25+
final var asJson = jsonb.toJson(bean);
26+
assertThat(asJson)
27+
.isEqualTo(
28+
"{\"a\":69,\"nested\":2,\"nested2\":3,\"nested3\":2,\"complex\":{\"id\":123,\"street\":\"avenue\"}}");
29+
30+
final var fromJson = jsonb.type(ValueInline.class).fromJson(asJson);
31+
32+
assertThat(fromJson.nested().nestB()).isEqualTo("idk");
33+
assertThat(fromJson.nested2().nestB()).isEqualTo("somethin");
34+
var fromAddress = fromJson.complex().address();
35+
assertThat(fromAddress.getId()).isEqualTo(address.getId());
36+
assertThat(fromAddress.getStreet()).isEqualTo(address.getStreet());
37+
}
38+
}

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

Lines changed: 0 additions & 132 deletions
This file was deleted.

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

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.util.*;
2121
import java.util.function.Predicate;
22+
import java.util.stream.Stream;
2223

2324
@GenerateAPContext
2425
@GenerateModuleInfoReader
@@ -36,7 +37,7 @@ public final class Processor extends AbstractProcessor {
3637
private final List<BeanReader> allReaders = new ArrayList<>();
3738
private final Set<String> sourceTypes = new HashSet<>();
3839
private final Set<String> mixInImports = new HashSet<>();
39-
private final Set<String> enumElements = new HashSet<>();
40+
private final Set<String> valueElements = new HashSet<>();
4041

4142
private SimpleComponentWriter componentWriter;
4243
private boolean readModuleInfo;
@@ -68,8 +69,8 @@ private void readModule() {
6869
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment round) {
6970
APContext.setProjectModuleElement(annotations, round);
7071
readModule();
72+
writeValueAdapters(round.getElementsAnnotatedWith(typeElement(ValuePrism.PRISM_TYPE)));
7173
writeAdapters(round.getElementsAnnotatedWith(typeElement(JSON)));
72-
writeEnumAdapters(round.getElementsAnnotatedWith(typeElement(ValuePrism.PRISM_TYPE)));
7374
writeAdaptersForMixInTypes(round.getElementsAnnotatedWith(typeElement(JSON_MIXIN)));
7475
writeAdaptersForImportedList(round.getElementsAnnotatedWith(typeElement(JSON_IMPORT_LIST)));
7576
writeAdaptersForImported(round.getElementsAnnotatedWith(typeElement(JSON_IMPORT)));
@@ -119,22 +120,44 @@ private static Predicate<VariableElement> isStaticFactory() {
119120
return v -> v.getModifiers().contains(Modifier.STATIC) && "FACTORY".equals(v.getSimpleName().toString());
120121
}
121122

122-
private void writeEnumAdapters(Set<? extends Element> elements) {
123+
private void writeValueAdapters(Set<? extends Element> elements) {
123124
for (final ExecutableElement element : ElementFilter.methodsIn(elements)) {
124125
final var typeElement = (TypeElement) element.getEnclosingElement();
125-
if (typeElement.getKind() != ElementKind.ENUM) {
126-
logError("@Json.Value is only for enum methods at: " + typeElement);
127-
} else {
128-
writeEnumAdapterForType(typeElement, element);
129-
}
126+
validateValue(element, typeElement);
127+
writeAdapter(typeElement, new ValueReader(typeElement, element));
130128
}
131129
}
132130

133-
private void writeEnumAdapterForType(TypeElement typeElement, ExecutableElement element) {
134-
if (!enumElements.add(typeElement.asType().toString())) {
135-
logError("@Json.Value can only be used once on a given enum methods at: " + typeElement);
131+
private void validateValue(final ExecutableElement element, final TypeElement typeElement) {
132+
if (!valueElements.add(typeElement.asType().toString())) {
133+
logError(typeElement, "@Json.Value can only be used once on a given type");
134+
} else if (!element.getParameters().isEmpty()) {
135+
logError(element, "@Json.Value can only be used on methods with no parameters");
136+
}
137+
if (typeElement.getKind() == ElementKind.ENUM) {
138+
return;
139+
}
140+
var returnType = Util.trimAnnotations(element.getReturnType().toString());
141+
142+
var methods =
143+
ElementFilter.methodsIn(typeElement.getEnclosedElements()).stream()
144+
.filter(CreatorPrism::isPresent);
145+
146+
final var constructors =
147+
ElementFilter.constructorsIn(typeElement.getEnclosedElements()).stream();
148+
149+
if (Stream.concat(methods, constructors)
150+
.filter(s -> s.getParameters().size() == 1)
151+
.map(s -> s.getParameters().get(0).asType().toString())
152+
.map(Util::trimAnnotations)
153+
.noneMatch(returnType::equals)) {
154+
155+
logError(
156+
typeElement,
157+
"Missing constructor or @Json.Creator factory method with signature %s(%s value)",
158+
Util.shortName(typeElement.getQualifiedName().toString()),
159+
Util.shortName(returnType));
136160
}
137-
writeAdapter(typeElement, new EnumReader(typeElement, element));
138161
}
139162

140163
private void cascadeTypes() {
@@ -154,7 +177,7 @@ private void cascadeTypesInner() {
154177
for (final String type : extraTypes) {
155178
if (!ignoreType(type)) {
156179
final TypeElement element = typeElement(type);
157-
if (cascadeElement(element)) {
180+
if (element != null && cascadeElement(element)) {
158181
writeAdapterForType(element);
159182
}
160183
}
@@ -259,6 +282,9 @@ private void writeAdapters(Set<? extends Element> beans) {
259282
}
260283

261284
private void writeAdapterForType(TypeElement typeElement) {
285+
if (valueElements.contains(typeElement.toString())) {
286+
return;
287+
}
262288
writeAdapter(typeElement, new ClassReader(typeElement));
263289
}
264290

0 commit comments

Comments
 (0)