Subtype resolution with unknown generics #442
-
Hi,
with a superclass of
this is the same problem as FasterXML/java-classmate#53. Given that there does not yet seem to be a general fix for this issue, I was wondering if anyone had any suggestions around writing specific handling code just for this exact case. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
This was being used in my custom subtype resolver and going from calling @Override
public List<ResolvedType> findSubtypes(ResolvedType declaredType, SchemaGenerationContext context) {
Collection<Class<?>> subtypes = <custom subtype fetching behavior>
if (resolvedSubtypes.isEmpty()) {
return null;
} else {
TypeContext typeContext = context.getTypeContext();
return resolvedSubtypes
.stream()
.map(subType -> typeContext.resolveSubtype(declaredType, subType))
.collect(Collectors.toList());
}
} to directly calling return resolvedSubtypes
.stream()
.map(typeContext::resolve)
.collect(Collectors.toList()); seemed to have worked. But would still appreciate it if someone could check if |
Beta Was this translation helpful? Give feedback.
-
Hi @CarstenWickner, I really appreciate the fast response, apologies my question was not super clear but your answer does clarify some things for me.
and an example of this (sorry this example is not super minimal, I am trying to make it as close to my code as possible in case there is something else I may have messed up on) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
interface Operation<T> {
String getType();
T getData();
}
@JsonTypeName("void")
class Void implements Operation<Optional<Void>> {
private final Optional<Void> data;
Void(Optional<Void> data) {
this.data = data;
}
@Override
public String getType() {
return "void";
}
@Override
@JsonProperty("data")
public Optional<Void> getData() {
return Optional.empty();
}
}
class MainObject {
private final Operation<?> operation;
MainObject(Operation<?> operation) {
this.operation = operation;
}
@JsonProperty("operation")
public Operation<?> getOperation() {
return operation;
}
} With this setup SchemaGeneratorConfigBuilder configBuilder =
new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON)
.with(new JacksonModule(JacksonOption.ALWAYS_REF_SUBTYPES));
configBuilder.forTypesInGeneral()
.withSubtypeResolver((declaredType, context) -> {
Class<?> type = declaredType.getErasedType();
Collection<Class<?>> resolvedSubtypes = // custom behavior to fetch Void as a subtype of Operation
if (resolvedSubtypes.isEmpty()) {
return null;
} else {
TypeContext typeContext = context.getTypeContext();
return resolvedSubtypes
.stream()
.map(typeContext::resolve)
.collect(Collectors.toList());
}
});
SchemaGenerator generator = new SchemaGenerator(configBuilder.build());
JsonNode jsonSchema =
generator.generateSchema(MainObject.class); I get the result {
"$schema" : "https://json-schema.org/draft/2019-09/schema",
"$defs" : {
"Void-1" : {
"type" : "object",
"properties" : {
"data" : {
"anyOf" : [ {
"type" : "null"
}, {
"$ref" : "#/$defs/Void-2"
} ]
}
}
},
"Void-2" : {
"$ref" : "#/$defs/Void-1",
"type" : "object",
"properties" : {
"type" : {
"const" : "void"
}
},
"required" : [ "type" ]
}
},
"type" : "object",
"properties" : {
"operation" : {
"$ref" : "#/$defs/Void-2"
}
}
} but if I change the subtype resolution to return resolvedSubtypes
.stream()
.map(clazz -> typeContext.resolveSubtype(declaredType, clazz))
.collect(Collectors.toList()); I get the error above |
Beta Was this translation helpful? Give feedback.
Hi @kevin-yu-0602,
I'm unsure how to respond here, honestly.
This seems different to FasterXML/java-classmate#53, since the issue described there would occur for this:
with a superclass of
The lack of type parameter declaration is the issue there.
In your specific example,
resolveSubtype
is not technically required, but it is the safe way to go, in case you have this kind of setup:and the member where the Subtype Resolver gets applied is something like this:
When you use
typeContext.resolve(Dog.class)
you interpret this as:Using
typeContext.resolveSubtype(…