Skip to content

Commit

Permalink
Explicitly support PROPERTY and EXISTING_PROPERTY in "includeAs" Jack…
Browse files Browse the repository at this point in the history
…son polymorphism

Fixes #103. Before, we included the "discriminator"
property twice if EXISTING_PROPERTY was used.
  • Loading branch information
neiser committed Jan 3, 2022
1 parent 34bf69c commit 3fc2672
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ public RecursionKey resolve(
if (jsonTypeInfo == null) {
return null;
}
JsonTypeInfo.As includeAs = jsonTypeInfo.include();
if (includeAs != JsonTypeInfo.As.PROPERTY && includeAs != JsonTypeInfo.As.EXISTING_PROPERTY) {
LOGGER.warn("Encountered unsupported JsonTypeInfo annotation with include = {}, will ignore", jsonTypeInfo.include());
return null;
}

String propertyName = findPropertyName(jsonTypeInfo);
Class<?> classOwningJsonTypeInfo = findClassOwningJsonTypeInfo(initialType.getType().getRawClass())
Expand Down Expand Up @@ -140,7 +145,7 @@ public RecursionKey resolve(

jsonSubTypes.forEach((typeName, type) -> schemaBuilderFromType.buildSchemaReferenceFromType(
objectMapper.constructType(type),
createAnnotationsSupplier(type, propertyName, jsonSubTypes.keySet(), propertySchemaName),
createAnnotationsSupplier(type, propertyName, jsonSubTypes.keySet(), propertySchemaName, includeAs),
schemaReference -> {
schemaReferenceMapping.put(typeName, schemaReference.getRef());
oneOfSchemas.set(oneOfSchemasIndexMap.get(typeName), schemaReference);
Expand All @@ -160,7 +165,9 @@ public RecursionKey resolve(

@Override
public Map<String, SchemaProperty> findProperties(SchemaResolver.Caller caller, JavaType javaType, AnnotationsSupplier annotationsSupplier) {
return annotationsSupplier.findAnnotations(PropertyNameAnnotation.class)
return annotationsSupplier.findAnnotations(PropertyIncludeAsAnnotation.class)
.filter(a -> a.value() == JsonTypeInfo.As.PROPERTY)
.flatMap(ignored -> annotationsSupplier.findAnnotations(PropertyNameAnnotation.class))
.findFirst()
.map(propertyNameAnnotation -> Collections.<String, SchemaProperty>singletonMap(
propertyNameAnnotation.value(), new SchemaProperty() {
Expand Down Expand Up @@ -199,7 +206,8 @@ public void customize(Schema schema, JavaType javaType, AnnotationsSupplier anno
if (!propertySchemaName.isPresent()) {
return;
}
properties.get(propertyName.get()).customize(
SchemaPropertyCallback schemaPropertyCallback = properties.get(propertyName.get());
schemaPropertyCallback.customize(
(propertySchema, propertyJavaType, propertyAnnotationsSupplier) -> {
propertySchema.setName(propertySchemaName.get());
propertySchema.setEnumValues(propertyEnumValues.get());
Expand All @@ -215,7 +223,7 @@ private JsonTypeInfo getJsonTypeInfo(Schema schema) {
return null;
}

private AnnotationsSupplier createAnnotationsSupplier(Class<?> type, String propertyName, Collection<String> propertyEnumValues, String propertySchemaName) {
private AnnotationsSupplier createAnnotationsSupplier(Class<?> type, String propertyName, Collection<String> propertyEnumValues, String propertySchemaName, JsonTypeInfo.As includeAs) {
AnnotationsSupplier annotationsSupplier = annotationsSupplierFactory.createFromAnnotatedElement(type);
return new AnnotationsSupplier() {
@Override
Expand All @@ -230,6 +238,8 @@ public <A extends Annotation> Stream<A> findAnnotations(Class<A> annotationType)
return Stream.of(annotationType.cast(PropertyEnumValuesAnnotation.FACTORY.apply(propertyEnumValues.toArray(new String[0]))));
} else if (PropertySchemaNameAnnotation.class.equals(annotationType)) {
return Stream.of(annotationType.cast(PropertySchemaNameAnnotation.FACTORY.apply(propertySchemaName)));
} else if (PropertyIncludeAsAnnotation.class.equals(annotationType)) {
return Stream.of(annotationType.cast(PropertyIncludeAsAnnotation.FACTORY.apply(includeAs)));
}
return annotationsSupplier.findAnnotations(annotationType);
}
Expand Down Expand Up @@ -312,6 +322,12 @@ public JacksonPolymorphismSchema(String name, JsonTypeInfo jsonTypeInfo) {
String value();
}

private @interface PropertyIncludeAsAnnotation {
Function<JsonTypeInfo.As, PropertyIncludeAsAnnotation> FACTORY = createAnnotationProxyWithValueFactory(PropertyIncludeAsAnnotation.class, JsonTypeInfo.As.class);

JsonTypeInfo.As value();
}

@Override
public int getOrder() {
return ORDER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Value;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -15,22 +17,26 @@ public Animal mapping1() {
return null;
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "DOG"),
@JsonSubTypes.Type(value = Cat.class, name = "CAT"),
})
private interface Animal {

@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
private abstract static class Animal {
private final String type;
}

@Value
private static class Dog {
String wuff;
private static class Dog extends Animal {
private Dog() {
super("DOG");
}
}

@Value
private static class Cat {
String meow;
private static class Cat extends Animal {
private Cat() {
super("CAT");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@
"properties": {
"type": {
"$ref": "#/components/schemas/App54Controller.AnimalType"
},
"wuff": {
"type": "string"
}
}
},
Expand All @@ -48,9 +45,6 @@
"properties": {
"type": {
"$ref": "#/components/schemas/App54Controller.AnimalType"
},
"meow": {
"type": "string"
}
}
},
Expand All @@ -73,4 +67,4 @@
}
}
}
}
}

0 comments on commit 3fc2672

Please sign in to comment.