-
Notifications
You must be signed in to change notification settings - Fork 962
feat(docservice): Support Jackson polymorphism annotations #6370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
I will investigate it. |
Adds a new `JacksonPolymorphismTypeInfoProvider` to generate correct JSON Schemas with `oneOf` and `discriminator` for polymorphic types annotated with `@JsonTypeInfo` and `@JsonSubTypes`.
4e4ea3c
to
ac2b9e3
Compare
core/src/test/java/com/linecorp/armeria/internal/server/annotation/AnnotatedDocServiceTest.java
Outdated
Show resolved
Hide resolved
core/src/test/java/com/linecorp/armeria/internal/server/annotation/AnnotatedDocServiceTest.java
Outdated
Show resolved
Hide resolved
...test/java/com/linecorp/armeria/internal/server/annotation/AnnotatedDocServicePluginTest.java
Outdated
Show resolved
Hide resolved
...ain/resources/META-INF/services/com.linecorp.armeria.server.docs.DescriptiveTypeInfoProvider
Outdated
Show resolved
Hide resolved
ac2b9e3
to
e7a0237
Compare
Adds a new `JacksonPolymorphismTypeInfoProvider` to generate correct JSON Schemas with `oneOf` and `discriminator` for polymorphic types annotated with `@JsonTypeInfo` and `@JsonSubTypes`.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #6370 +/- ##
============================================
- Coverage 74.46% 74.05% -0.42%
- Complexity 22234 23003 +769
============================================
Files 1963 2064 +101
Lines 82437 86224 +3787
Branches 10764 11332 +568
============================================
+ Hits 61385 63851 +2466
- Misses 15918 16938 +1020
- Partials 5134 5435 +301 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
logger.info("JSON Specification: http://127.0.0.1:8080/docs/specification.json"); | ||
} | ||
|
||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "species") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the subtypes are missing species
, so deserialization actually doesn't work.
Also, this is not a tutorial, but just an example.
So, what do you think of making this class a test case (PolymorphismDocServiceTest) like we did for AnnotatedDocServiceTest
?
We can use TestUtil.isDocServiceDemoMode()
to see how it works on a browser.
Could you also use English for comments instead of Korean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few more suggestions. 😎
Please, keep up the great work. 👍
core/src/main/java/com/linecorp/armeria/server/docs/DiscriminatorInfo.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/docs/DocServiceTypeUtil.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/docs/JacksonPolymorphismTypeInfoProvider.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/docs/JacksonPolymorphismTypeInfoProvider.java
Show resolved
Hide resolved
} | ||
|
||
final Map<String, String> mapping = new LinkedHashMap<>(); | ||
Arrays.stream(jsonSubTypes.value()).forEach(subType -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also handle the case where jsonSubTypes.value()
is empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for question regarding the empty subTypes
case.
Here is a summary of my findings.
Test Setup
I created a misconfigured DTO specifically for this test:
// DTO with an intentionally empty @JsonSubTypes annotation
@JsonTypeInfo(use = JsonTypeTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({})
interface MisconfiguredAnimal {
String name();
}
1. Current Code
With the current implementation, when DocService
processes MisconfiguredAnimal
, it generates the following StructInfo
in specification.json
:
- The
oneOf
field is missing. This is because the list is empty and the field is annotated with@JsonInclude(Include.NON_EMPTY)
. - The
discriminator
field is present, but itsmapping
is an empty object.
Resulting StructInfo
snippet:
"name" : "...MisconfiguredAnimal",
"fields" : [ ],
"descriptionInfo" : {
"docString" : "",
"markup" : "NONE"
},
"discriminator" : {
"propertyName" : "type",
"mapping" : { }
}
This result seems inconsistent, as it describes a discriminator without any subtypes in oneOf
.
2. After adding return null
After adding defensive check to JacksonPolymorphismTypeInfoProvider
:
if (jsonSubTypes.value().length == 0) {
return null;
}
final Map<String, String> mapping = new LinkedHashMap<>();
...
The provider returns null
for MisconfiguredAnimal
. The request then falls back to DefaultDescriptiveTypeInfoProvider
, which correctly treats it as a generic interface.
Resulting StructInfo
snippet:
{
"name" : "...MisconfiguredAnimal",
"fields" : [ ],
"descriptionInfo" : {
"docString" : "",
"markup" : "NONE"
}
}
This result is clean and does not contain any misleading or incomplete polymorphism information.
Conclusion & Question
i think second one looks better, can i do this?
Thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think second one looks better, can i do this?
Yeah, that looks good. 👍
if (structInfo != null) { | ||
visited.put(firstParam.typeSignature(), "#"); | ||
generateProperties(structInfo.fields(), visited, "#", root); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we warn if structInfo == null
?
core/src/main/java/com/linecorp/armeria/server/docs/JsonSchemaGenerator.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/docs/JsonSchemaGenerator.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/docs/JsonSchemaGenerator.java
Show resolved
Hide resolved
fieldNode.set("additionalProperties", additionalPropertiesNode.get("")); | ||
} | ||
break; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happends if the type is other types such as CONTAINER
?
Adds a new `JacksonPolymorphismTypeInfoProvider` to generate correct JSON Schemas with `oneOf` and `discriminator` for polymorphic types annotated with `@JsonTypeInfo` and `@JsonSubTypes`.
Motivation
This pull request implements support for Jackson's polymorphism annotations (
@JsonTypeInfo
,@JsonSubTypes
) inDocService
, as requested in the community (issue #6313). Currently,DocService
does not correctly generate documentation for annotated services that use inheritance in their DTOs, leading to incomplete specifications. This change adds a newDescriptiveTypeInfoProvider
to resolve these polymorphic types and generate accurate JSON Schemas.However, this feature has uncovered significant and complex build stability issues when running a full parallel build (
./gradlew clean build --parallel
). This PR serves as both the implementation of the feature and a concrete test case for discussing the build instability it triggers.Modifications
JacksonPolymorphismTypeInfoProvider
: A new provider that uses pure Java reflection to safely inspect@JsonTypeInfo
and@JsonSubTypes
annotations. It is registered via Java's SPI mechanism to be discoverable byDocService
.DiscriminatorInfo
: A new data class to hold polymorphism metadata extracted from the annotations.toTypeSignature
) was moved from a separateDocServiceTypeUtil
intoAnnotatedDocServicePlugin
for better cohesion.StructInfo
: Modified to includeoneOf
anddiscriminator
fields to carry polymorphism information.JsonSchemaGenerator
: The generator now recognizes the new fields inStructInfo
and correctly produces JSON Schema withoneOf
anddiscriminator
properties.PolymorphismDocServiceExample
: A new example service to demonstrate and manually verify the feature.Result
DocService
can now correctly generate documentation for annotated services that use polymorphic types with Jackson. The resulting JSON Schema will contain the appropriateoneOf
anddiscriminator
fields.Known Issue: This change is known to trigger build instability in the project's CI environment. A detailed summary of the investigation is provided here : Request Guidance on Build Issues in my feature branch #6369Example usage
also, you can try this at PolymorphismDocServiceExample