Skip to content

Commit 10d05a4

Browse files
committed
refs #3409 - fix jsonValue processing
1 parent 17673cd commit 10d05a4

File tree

3 files changed

+104
-7
lines changed

3 files changed

+104
-7
lines changed

modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
import javax.xml.bind.annotation.XmlRootElement;
6767
import java.io.IOException;
6868
import java.lang.annotation.Annotation;
69+
import java.lang.reflect.InvocationTargetException;
70+
import java.lang.reflect.Method;
6971
import java.lang.reflect.Type;
7072
import java.math.BigDecimal;
7173
import java.util.ArrayList;
@@ -354,12 +356,11 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
354356
}
355357
}
356358

357-
// using deprecated method to maintain compatibility with jackson version < 2.9
358-
//alternatively use AnnotatedMember jsonValueMember = beanDesc.findJsonValueAccessor();
359-
final AnnotatedMethod jsonValueMethod = beanDesc.findJsonValueMethod();
360-
if(jsonValueMethod != null) {
359+
Type jsonValueType = findJsonValueType(beanDesc);
360+
361+
if(jsonValueType != null) {
361362
AnnotatedType aType = new AnnotatedType()
362-
.type(jsonValueMethod.getType())
363+
.type(jsonValueType)
363364
.parent(annotatedType.getParent())
364365
.name(annotatedType.getName())
365366
.schemaProperty(annotatedType.isSchemaProperty())
@@ -873,6 +874,26 @@ private boolean shouldResolveEnumAsRef(io.swagger.v3.oas.annotations.media.Schem
873874
return (resolvedSchemaAnnotation != null && resolvedSchemaAnnotation.enumAsRef()) || ModelResolver.enumsAsRef;
874875
}
875876

877+
protected Type findJsonValueType(final BeanDescription beanDesc) {
878+
879+
// use recursion to check for method findJsonValueAccessor existence (Jackson 2.9+)
880+
// if not found use previous deprecated method which could lead to inaccurate result
881+
try {
882+
Method m = BeanDescription.class.getMethod("findJsonValueAccessor", null);
883+
AnnotatedMember jsonValueMember = (AnnotatedMember)m.invoke(beanDesc, null);
884+
if (jsonValueMember != null) {
885+
return jsonValueMember.getType();
886+
}
887+
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
888+
LOGGER.warn("jackson BeanDescription.findJsonValueAccessor not found, this could lead to inaccurate result, please update jackson to 2.9+");
889+
final AnnotatedMethod jsonValueMethod = beanDesc.findJsonValueMethod();
890+
if (jsonValueMethod != null) {
891+
return jsonValueMethod.getType();
892+
}
893+
}
894+
return null;
895+
}
896+
876897
private Schema clone(Schema property) {
877898
if(property == null)
878899
return property;

modules/swagger-core/src/main/java/io/swagger/v3/core/util/ObjectMapperFactory.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ public static ObjectMapper buildStrictGenericObjectMapper() {
151151
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
152152
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
153153
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
154-
mapper.configure(DeserializationFeature.FAIL_ON_TRAILING_TOKENS, true);
154+
try {
155+
mapper.configure(DeserializationFeature.valueOf("FAIL_ON_TRAILING_TOKENS"), true);
156+
} catch (Throwable e) {
157+
// add only if supported by Jackson version 2.9+
158+
}
155159
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
156160
return mapper;
157161
}

modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/SimpleGenerationTest.java

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,26 @@
44
import com.fasterxml.jackson.annotation.JsonIgnore;
55
import com.fasterxml.jackson.annotation.JsonProperty;
66
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
7+
import com.fasterxml.jackson.annotation.JsonValue;
8+
import com.fasterxml.jackson.databind.BeanDescription;
9+
import com.fasterxml.jackson.databind.DeserializationFeature;
710
import com.fasterxml.jackson.databind.ObjectMapper;
811
import io.swagger.v3.core.converter.AnnotatedType;
912
import io.swagger.v3.core.converter.ModelConverterContextImpl;
13+
import io.swagger.v3.core.converter.ModelConverters;
1014
import io.swagger.v3.core.jackson.ModelResolver;
11-
import io.swagger.v3.core.util.Yaml;
1215
import io.swagger.v3.oas.models.media.Schema;
1316
import org.testng.annotations.Test;
1417

18+
import java.lang.reflect.Method;
1519
import java.util.ArrayList;
1620
import java.util.Arrays;
1721
import java.util.Date;
1822
import java.util.Map;
1923

2024
import static org.testng.Assert.assertEquals;
2125
import static org.testng.Assert.assertNotNull;
26+
import static org.testng.Assert.assertNull;
2227
import static org.testng.Assert.fail;
2328

2429
public class SimpleGenerationTest extends SwaggerTestBase {
@@ -104,8 +109,36 @@ public void testIntArray() throws Exception {
104109
assertEquals(prop.getType(), "array");
105110
}
106111

112+
113+
114+
protected boolean isJacksonAtLeast2_9() throws NoSuchMethodException {
115+
116+
try {
117+
Method m = BeanDescription.class.getMethod("findJsonValueAccessor", null);
118+
} catch (NoSuchMethodException e) {
119+
return false;
120+
}
121+
return true;
122+
}
123+
124+
125+
126+
@Test
127+
public void testJsonValue_Ticket3409() throws Exception {
128+
129+
DeserializationFeature aa = DeserializationFeature.valueOf("FAIL_ON_UNKNOWN_PROPERTIES");
130+
131+
Map<String, Schema> models = ModelConverters.getInstance().readAll(PlanetName.Planet.class);
132+
assertNotNull(models.get("Planet"));
133+
if (isJacksonAtLeast2_9()) {
134+
assertNull(models.get("PlanetName"));
135+
assertEquals(((Schema) models.get("Planet").getProperties().get("name")).getType(), "string");
136+
}
137+
}
138+
107139
@Test
108140
public void testComplex() throws Exception {
141+
109142
final Schema model = context.resolve(new AnnotatedType(ComplexBean.class));
110143
assertNotNull(model);
111144
final Map<String, Schema> props = model.getProperties();
@@ -208,4 +241,43 @@ public String getJ() {
208241
}
209242
}
210243

244+
245+
static class PlanetName {
246+
247+
@JsonValue
248+
private final String value;
249+
250+
@JsonCreator
251+
private PlanetName(String value) {
252+
this.value = value;
253+
}
254+
255+
public static PlanetName valueOf(String value) {
256+
return new PlanetName(value);
257+
}
258+
259+
public String getValue() {
260+
return value;
261+
}
262+
263+
@Override
264+
public String toString() {
265+
return value;
266+
}
267+
268+
269+
static class Planet {
270+
271+
private PlanetName name;
272+
273+
public PlanetName getName() {
274+
return name;
275+
}
276+
277+
public void setName(PlanetName name) {
278+
this.name = name;
279+
}
280+
}
281+
}
282+
211283
}

0 commit comments

Comments
 (0)