Skip to content
This repository was archived by the owner on Oct 16, 2024. It is now read-only.

Commit 197d43f

Browse files
authored
#417 Support @JsonAnyGetter
2 parents adec063 + ba8c441 commit 197d43f

File tree

9 files changed

+455
-35
lines changed

9 files changed

+455
-35
lines changed

build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ configurations {
192192
dependencies {
193193
vanillaCompile guava
194194
vanillaCompile gwtUser
195+
vanillaCompile jackson('core')
196+
vanillaCompile jackson('databind')
195197
vanillaTestCompile junit
196198
}
197199
task vanillaTest {

generated/main/java/org/inferred/freebuilder/processor/property/Property_Builder.java

+331-25
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.inferred.freebuilder;
2+
3+
import com.fasterxml.jackson.annotation.JsonAnyGetter;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.fasterxml.jackson.databind.JsonNode;
6+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
7+
8+
import java.util.Map;
9+
10+
@FreeBuilder
11+
@JsonDeserialize(builder = JacksonAnyGetterType.Builder.class)
12+
public interface JacksonAnyGetterType {
13+
@JsonProperty("simple_property")
14+
String getSimpleProperty();
15+
@JsonAnyGetter
16+
Map<String, JsonNode> getUnknownProperties();
17+
18+
class Builder extends JacksonAnyGetterType_Builder {}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.inferred.freebuilder;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.databind.node.IntNode;
6+
import com.fasterxml.jackson.databind.node.TextNode;
7+
import org.junit.Test;
8+
9+
import java.io.IOException;
10+
11+
import static org.junit.Assert.assertEquals;
12+
import static org.junit.Assert.assertNotNull;
13+
import static org.junit.Assert.assertTrue;
14+
15+
public class JacksonAnyGetterTypeTest {
16+
17+
private final ObjectMapper objectMapper = new ObjectMapper();
18+
19+
@Test
20+
public void testDeserializeJsonWithAnyGetter() throws IOException {
21+
JacksonAnyGetterType parsed = objectMapper.readValue(
22+
"{\"simple_property\": \"simpleValue\", \"other_property\": 3}",
23+
JacksonAnyGetterType.class);
24+
25+
assertEquals("simpleValue", parsed.getSimpleProperty());
26+
assertNotNull(parsed.getUnknownProperties());
27+
assertEquals(1, parsed.getUnknownProperties().size());
28+
assertEquals(new IntNode(3), parsed.getUnknownProperties().get("other_property"));
29+
}
30+
31+
@Test
32+
public void testSerializeJsonWithAnyGetter() throws JsonProcessingException {
33+
JacksonAnyGetterType getterType = new JacksonAnyGetterType.Builder()
34+
.setSimpleProperty("checkValue")
35+
.putUnknownProperties("propertyOne", new TextNode("abc"))
36+
.putUnknownProperties("propertyTwo", new IntNode(2)).build();
37+
38+
String json = objectMapper.writeValueAsString(getterType);
39+
assertTrue("should contain simple_property",
40+
json.contains("\"simple_property\":\"checkValue\""));
41+
assertTrue("should contain propertyOne", json.contains("\"propertyOne\":\"abc\""));
42+
assertTrue("should contain propertyTwo", json.contains("\"propertyTwo\":2"));
43+
}
44+
45+
}

src/main/java/org/inferred/freebuilder/processor/JacksonSupport.java

+30-7
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,24 @@
1919

2020
class JacksonSupport {
2121

22+
private enum GenerateAnnotation {
23+
DEFAULT,
24+
JSON_ANY,
25+
NONE
26+
}
27+
2228
private static final String JSON_DESERIALIZE =
2329
"com.fasterxml.jackson.databind.annotation.JsonDeserialize";
2430
private static final QualifiedName JSON_PROPERTY =
2531
QualifiedName.of("com.fasterxml.jackson.annotation", "JsonProperty");
2632
private static final String JACKSON_XML_ANNOTATION_PACKAGE =
2733
"com.fasterxml.jackson.dataformat.xml.annotation";
34+
private static final QualifiedName JSON_ANY_GETTER =
35+
QualifiedName.of("com.fasterxml.jackson.annotation", "JsonAnyGetter");
36+
private static final QualifiedName JSON_ANY_SETTER =
37+
QualifiedName.of("com.fasterxml.jackson.annotation", "JsonAnySetter");
2838
/** Annotations which disable automatic generation of JsonProperty annotations. */
2939
private static final Set<QualifiedName> DISABLE_PROPERTY_ANNOTATIONS = ImmutableSet.of(
30-
QualifiedName.of("com.fasterxml.jackson.annotation", "JsonAnyGetter"),
3140
QualifiedName.of("com.fasterxml.jackson.annotation", "JsonIgnore"),
3241
QualifiedName.of("com.fasterxml.jackson.annotation", "JsonUnwrapped"),
3342
QualifiedName.of("com.fasterxml.jackson.annotation", "JsonValue"));
@@ -50,9 +59,20 @@ public void addJacksonAnnotations(
5059
JSON_PROPERTY);
5160
if (jsonPropertyAnnotation.isPresent()) {
5261
resultBuilder.addAccessorAnnotations(Excerpts.add("%s%n", jsonPropertyAnnotation.get()));
53-
} else if (generateDefaultAnnotations(getterMethod)) {
54-
resultBuilder.addAccessorAnnotations(Excerpts.add(
55-
"@%s(\"%s\")%n", JSON_PROPERTY, resultBuilder.getName()));
62+
} else {
63+
switch (generateDefaultAnnotations(getterMethod)) {
64+
case DEFAULT:
65+
resultBuilder.addAccessorAnnotations(Excerpts.add(
66+
"@%s(\"%s\")%n", JSON_PROPERTY, resultBuilder.getName()));
67+
break;
68+
case JSON_ANY:
69+
resultBuilder.addPutAnnotations(Excerpts.add("@%s%n", JSON_ANY_SETTER));
70+
resultBuilder.addGetterAnnotations(Excerpts.add("@%s%n", JSON_ANY_GETTER));
71+
break;
72+
case NONE:
73+
default:
74+
break;
75+
}
5676
}
5777

5878
getterMethod
@@ -69,15 +89,18 @@ private boolean isXmlAnnotation(AnnotationMirror mirror) {
6989
return pkg.contentEquals(JACKSON_XML_ANNOTATION_PACKAGE);
7090
}
7191

72-
private static boolean generateDefaultAnnotations(ExecutableElement getterMethod) {
92+
private static GenerateAnnotation generateDefaultAnnotations(ExecutableElement getterMethod) {
7393
for (AnnotationMirror annotationMirror : getterMethod.getAnnotationMirrors()) {
7494
TypeElement annotationTypeElement =
7595
(TypeElement) (annotationMirror.getAnnotationType().asElement());
7696
QualifiedName annotationType = QualifiedName.of(annotationTypeElement);
7797
if (DISABLE_PROPERTY_ANNOTATIONS.contains(annotationType)) {
78-
return false;
98+
return GenerateAnnotation.NONE;
99+
}
100+
if (JSON_ANY_GETTER.equals(annotationType)) {
101+
return GenerateAnnotation.JSON_ANY;
79102
}
80103
}
81-
return true;
104+
return GenerateAnnotation.DEFAULT;
82105
}
83106
}

src/main/java/org/inferred/freebuilder/processor/property/MapProperty.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,9 @@ private void addPut(SourceBuilder code) {
192192
}
193193
code.add(" null\n");
194194
}
195-
code.addLine(" */")
196-
.addLine("public %s %s(%s key, %s value) {",
195+
code.addLine(" */");
196+
addPutAnnotations(code);
197+
code.addLine("public %s %s(%s key, %s value) {",
197198
datatype.getBuilder(),
198199
putMethod(property),
199200
unboxedKeyType.orElse(keyType),

src/main/java/org/inferred/freebuilder/processor/property/NullableProperty.java

+1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ public Set<MergeAction> getMergeActions() {
214214

215215
@Override
216216
public void addGetterAnnotations(SourceBuilder code) {
217+
super.addGetterAnnotations(code);
217218
for (TypeElement nullableAnnotation : nullables) {
218219
code.add("@%s ", nullableAnnotation);
219220
}

src/main/java/org/inferred/freebuilder/processor/property/Property.java

+13
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ public FieldAccess getField() {
6262
*/
6363
public abstract ImmutableList<Excerpt> getAccessorAnnotations();
6464

65+
/**
66+
* Returns a list of annotations that should be applied to the getter method of this
67+
* property.
68+
*/
69+
public abstract ImmutableList<Excerpt> getGetterAnnotations();
70+
71+
/**
72+
* Returns a list of annotations that should be applied to the put method of this
73+
* property. This only applies to map properties.
74+
* Annotation will be added to put(key, value) method.
75+
*/
76+
public abstract ImmutableList<Excerpt> getPutAnnotations();
77+
6578
public Property.Builder toBuilder() {
6679
return new Builder().mergeFrom(this);
6780
}

src/main/java/org/inferred/freebuilder/processor/property/PropertyCodeGenerator.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ public void addPartialFieldAssignment(
166166
public abstract Set<MergeAction> getMergeActions();
167167

168168
/** Adds method annotations for the value type getter method. */
169-
public void addGetterAnnotations(@SuppressWarnings("unused") SourceBuilder code) {}
169+
public void addGetterAnnotations(SourceBuilder code) {
170+
for (Excerpt annotation : property.getGetterAnnotations()) {
171+
code.add(annotation);
172+
}
173+
}
170174

171175
/** Adds a fragment converting the value object's field to the property's type. */
172176
public void addReadValueFragment(SourceBuilder code, Excerpt finalField) {
@@ -203,6 +207,12 @@ public void addAccessorAnnotations(SourceBuilder code) {
203207
}
204208
}
205209

210+
public void addPutAnnotations(SourceBuilder code) {
211+
for (Excerpt annotation : property.getPutAnnotations()) {
212+
code.add(annotation);
213+
}
214+
}
215+
206216
@Override
207217
public boolean equals(Object obj) {
208218
if (obj == null || !getClass().isInstance(obj)) {

0 commit comments

Comments
 (0)