Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit 201db70

Browse files
authored
json subtypes support (#146)
* json subtypes support * json subtypes example * regenerated html after merge
1 parent 7d3a1f5 commit 201db70

File tree

19 files changed

+811
-332
lines changed

19 files changed

+811
-332
lines changed

docs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,7 @@ <h4 id="contributing-building-build"><a class="link" href="#contributing-buildin
16371637
</div>
16381638
<div id="footer">
16391639
<div id="footer-text">
1640-
Last updated 2017-10-22 18:16:36 CEST
1640+
Last updated 2017-10-23 13:03:37 CEST
16411641
</div>
16421642
</div>
16431643
<link rel="stylesheet" href="highlight/styles/github.min.css">

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/jackson/FieldDocumentationArrayVisitor.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,37 @@
1616

1717
package capital.scalable.restdocs.jackson;
1818

19-
import java.util.Set;
20-
2119
import com.fasterxml.jackson.databind.JavaType;
2220
import com.fasterxml.jackson.databind.JsonMappingException;
2321
import com.fasterxml.jackson.databind.SerializerProvider;
2422
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonArrayFormatVisitor;
2523
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitable;
2624
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
25+
import com.fasterxml.jackson.databind.type.TypeFactory;
2726

28-
public class FieldDocumentationArrayVisitor extends JsonArrayFormatVisitor.Base {
27+
class FieldDocumentationArrayVisitor extends JsonArrayFormatVisitor.Base {
2928

3029
private final FieldDocumentationVisitorContext context;
3130
private final String path;
32-
private final Set<JavaType> visited;
31+
private final TypeRegistry typeRegistry;
32+
private final TypeFactory typeFactory;
3333

3434
public FieldDocumentationArrayVisitor(SerializerProvider provider,
35-
FieldDocumentationVisitorContext context, String path, Set<JavaType> visited) {
35+
FieldDocumentationVisitorContext context, String path, TypeRegistry typeRegistry,
36+
TypeFactory typeFactory) {
3637
super(provider);
3738
this.context = context;
3839
this.path = path;
39-
this.visited = visited;
40+
this.typeRegistry = typeRegistry;
41+
this.typeFactory = typeFactory;
4042
}
4143

4244
@Override
4345
public void itemsFormat(JsonFormatVisitable handler, JavaType elementType)
4446
throws JsonMappingException {
4547
String elementPath = path + "[]";
4648
JsonFormatVisitorWrapper visitor = new FieldDocumentationVisitorWrapper(getProvider(),
47-
context, elementPath, null, visited);
49+
context, elementPath, null, typeRegistry, typeFactory);
4850
handler.acceptJsonFormatVisitor(visitor, elementType);
4951
}
5052
}

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/jackson/FieldDocumentationGenerator.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package capital.scalable.restdocs.jackson;
1818

19+
import static capital.scalable.restdocs.util.TypeUtil.resolveAllTypes;
20+
import static org.slf4j.LoggerFactory.getLogger;
21+
1922
import java.lang.reflect.Type;
2023
import java.util.List;
2124

@@ -26,9 +29,11 @@
2629
import com.fasterxml.jackson.databind.JsonMappingException;
2730
import com.fasterxml.jackson.databind.ObjectWriter;
2831
import com.fasterxml.jackson.databind.type.TypeFactory;
32+
import org.slf4j.Logger;
2933
import org.springframework.restdocs.payload.FieldDescriptor;
3034

3135
public class FieldDocumentationGenerator {
36+
private static final Logger log = getLogger(FieldDocumentationGenerator.class);
3237

3338
private final ObjectWriter writer;
3439
private final DeserializationConfig deserializationConfig;
@@ -45,15 +50,20 @@ public FieldDocumentationGenerator(ObjectWriter writer,
4550
this.constraintReader = constraintReader;
4651
}
4752

48-
public List<FieldDescriptor> generateDocumentation(Type type, TypeFactory typeFactory)
53+
public List<FieldDescriptor> generateDocumentation(Type baseType, TypeFactory typeFactory)
4954
throws JsonMappingException {
50-
return generateDocumentation(typeFactory.constructType(type));
51-
}
55+
JavaType javaBaseType = typeFactory.constructType(baseType);
56+
List<JavaType> types = resolveAllTypes(javaBaseType, typeFactory);
5257

53-
public List<FieldDescriptor> generateDocumentation(JavaType type) throws JsonMappingException {
5458
FieldDocumentationVisitorWrapper visitorWrapper = FieldDocumentationVisitorWrapper.create(
55-
javadocReader, constraintReader, deserializationConfig);
56-
writer.acceptJsonFormatVisitor(type, visitorWrapper);
57-
return visitorWrapper.getContext().getFields();
59+
javadocReader, constraintReader, deserializationConfig,
60+
new TypeRegistry(types), typeFactory);
61+
62+
for (JavaType type : types) {
63+
log.debug("(TOP) {}", type.getRawClass().getSimpleName());
64+
writer.acceptJsonFormatVisitor(type, visitorWrapper);
65+
}
66+
67+
return visitorWrapper.getFields();
5868
}
59-
}
69+
}

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/jackson/FieldDocumentationObjectVisitor.java

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717
package capital.scalable.restdocs.jackson;
1818

19-
import java.util.Set;
19+
import static capital.scalable.restdocs.util.TypeUtil.resolveAllTypes;
20+
import static org.slf4j.LoggerFactory.getLogger;
2021

2122
import com.fasterxml.jackson.databind.BeanProperty;
2223
import com.fasterxml.jackson.databind.JavaType;
@@ -25,60 +26,61 @@
2526
import com.fasterxml.jackson.databind.SerializerProvider;
2627
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
2728
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
28-
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
29+
import com.fasterxml.jackson.databind.type.TypeFactory;
30+
import org.slf4j.Logger;
31+
import org.springframework.util.Assert;
2932

30-
public class FieldDocumentationObjectVisitor extends JsonObjectFormatVisitor.Base {
33+
class FieldDocumentationObjectVisitor extends JsonObjectFormatVisitor.Base {
34+
private static final Logger log = getLogger(FieldDocumentationObjectVisitor.class);
3135

3236
private final FieldDocumentationVisitorContext context;
3337
private final String path;
34-
private final Set<JavaType> visited;
38+
private final TypeRegistry typeRegistry;
39+
private final TypeFactory typeFactory;
3540

3641
public FieldDocumentationObjectVisitor(SerializerProvider provider,
37-
FieldDocumentationVisitorContext context, String path, Set<JavaType> visited) {
42+
FieldDocumentationVisitorContext context, String path, TypeRegistry typeRegistry,
43+
TypeFactory typeFactory) {
3844
super(provider);
3945
this.context = context;
4046
this.path = path;
41-
this.visited = visited;
47+
this.typeRegistry = typeRegistry;
48+
this.typeFactory = typeFactory;
4249
}
4350

4451
@Override
4552
public void optionalProperty(BeanProperty prop) throws JsonMappingException {
4653
String jsonName = prop.getName();
4754
String fieldName = prop.getMember().getName();
4855

49-
JavaType type = prop.getType();
50-
if (type == null) {
51-
throw new IllegalStateException("Missing type for property '" + jsonName + "', " +
52-
"field '" + fieldName + "'");
53-
}
56+
JavaType baseType = prop.getType();
57+
Assert.notNull(baseType,
58+
"Missing type for property '" + jsonName + "', field '" + fieldName + "'");
59+
60+
for (JavaType javaType : resolveAllTypes(baseType, typeFactory)) {
61+
JsonSerializer<?> ser = getProvider().findValueSerializer(javaType, prop);
62+
if (ser == null) {
63+
return;
64+
}
5465

55-
JsonSerializer<?> ser = getSer(prop);
56-
if (ser == null) {
57-
return;
66+
visitType(prop, jsonName, fieldName, javaType, ser);
5867
}
68+
}
5969

70+
private void visitType(BeanProperty prop, String jsonName, String fieldName, JavaType fieldType,
71+
JsonSerializer<?> ser) throws JsonMappingException {
6072
String fieldPath = path + (path.isEmpty() ? "" : ".") + jsonName;
73+
log.debug("({}) {}", fieldPath, fieldType.getRawClass().getSimpleName());
6174
Class<?> javaBaseClass = prop.getMember().getDeclaringClass();
6275
boolean shouldExpand = shouldExpand(prop);
6376

64-
InternalFieldInfo fieldInfo = new InternalFieldInfo(javaBaseClass, fieldName, fieldPath,
65-
shouldExpand);
77+
InternalFieldInfo fieldInfo = new InternalFieldInfo(javaBaseClass, fieldName, fieldType,
78+
fieldPath, shouldExpand);
6679

6780
JsonFormatVisitorWrapper visitor = new FieldDocumentationVisitorWrapper(getProvider(),
68-
context, fieldPath, fieldInfo, visited);
81+
context, fieldPath, fieldInfo, typeRegistry, typeFactory);
6982

70-
ser.acceptJsonFormatVisitor(visitor, type);
71-
}
72-
73-
protected JsonSerializer<?> getSer(BeanProperty prop) throws JsonMappingException {
74-
JsonSerializer<Object> ser = null;
75-
if (prop instanceof BeanPropertyWriter) {
76-
ser = ((BeanPropertyWriter) prop).getSerializer();
77-
}
78-
if (ser == null) {
79-
ser = getProvider().findValueSerializer(prop.getType(), prop);
80-
}
81-
return ser;
83+
ser.acceptJsonFormatVisitor(visitor, fieldType);
8284
}
8385

8486
private boolean shouldExpand(BeanProperty prop) {

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/jackson/FieldDocumentationVisitorContext.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static capital.scalable.restdocs.util.FieldUtil.isGetter;
2323
import static capital.scalable.restdocs.util.TypeUtil.isPrimitive;
2424
import static org.apache.commons.lang3.StringUtils.isBlank;
25+
import static org.slf4j.LoggerFactory.getLogger;
2526
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
2627

2728
import java.util.ArrayList;
@@ -31,10 +32,13 @@
3132
import capital.scalable.restdocs.javadoc.JavadocReader;
3233
import com.fasterxml.jackson.databind.DeserializationConfig;
3334
import com.fasterxml.jackson.databind.DeserializationFeature;
35+
import org.slf4j.Logger;
3436
import org.springframework.restdocs.payload.FieldDescriptor;
3537
import org.springframework.restdocs.snippet.Attributes.Attribute;
3638

37-
public class FieldDocumentationVisitorContext {
39+
class FieldDocumentationVisitorContext {
40+
private static final Logger log = getLogger(FieldDocumentationVisitorContext.class);
41+
3842
private final List<FieldDescriptor> fields = new ArrayList<>();
3943
private final JavadocReader javadocReader;
4044
private final ConstraintReader constraintReader;
@@ -53,11 +57,16 @@ public List<FieldDescriptor> getFields() {
5357
}
5458

5559
public void addField(InternalFieldInfo info, String jsonType) {
60+
String jsonFieldPath = info.getJsonFieldPath();
61+
String javaFieldTypeName = info.getJavaFieldType().getRawClass().getSimpleName();
62+
63+
if (isPresent(jsonFieldPath, javaFieldTypeName)) {
64+
return; // do not add duplicates
65+
}
66+
5667
Class<?> javaBaseClass = info.getJavaBaseClass();
5768
String javaFieldName = info.getJavaFieldName();
58-
5969
String comment = resolveComment(javaBaseClass, javaFieldName);
60-
String jsonFieldPath = info.getJsonFieldPath();
6170

6271
FieldDescriptor fieldDescriptor = fieldWithPath(jsonFieldPath)
6372
.type(jsonType)
@@ -68,6 +77,20 @@ public void addField(InternalFieldInfo info, String jsonType) {
6877
fieldDescriptor.attributes(constraints, optionals);
6978

7079
fields.add(fieldDescriptor);
80+
log.debug("({}) {} added", jsonFieldPath, javaFieldTypeName);
81+
}
82+
83+
private boolean isPresent(String jsonFieldPath, String javaFieldTypeName) {
84+
log.trace(" = WAS ADDED? {}", jsonFieldPath);
85+
for (FieldDescriptor descriptor : fields) {
86+
if (descriptor.getPath().equals(jsonFieldPath)) {
87+
log.trace(" = YES {}", descriptor.getPath());
88+
log.debug("({}) {} NOT added", jsonFieldPath, javaFieldTypeName);
89+
return true;
90+
}
91+
log.trace(" = NO {}", descriptor.getPath());
92+
}
93+
return false;
7194
}
7295

7396
private String resolveComment(Class<?> javaBaseClass, String javaFieldName) {

0 commit comments

Comments
 (0)