Annotate POJOs that always serialize as primitives
I am using v2.9.2 and have been unable to identify a way to mark a POJO as a primitive. I end up with a swagger definition that sees the value as an object, and lists out the properties within it which my API consumers should not know about. I've specified Jackson to always consume or produce primitive JSON from these POJOs, such as a string or number, but what I am missing is a corresponding Swagger annotation.
I saw @ApiModelProperty(dataType = "java.lang.String") etc. to do this one-off for a property within an object, but I need this class to be a primitive regardless of whether it is nested, and without needing to annotate every usage of it.
If a solution doesn't already exist, I am happy to propose some ideas and possibly contribute if the path for doing that is fairly clear.
The main reason I have to do this is HL7 FHIR, which specifies highly constrained primitive types in JSON. Some examples include strings representing identifiers. They can't have spaces or be longer than 64 characters, have to match a regex, and sometimes more. Similar constraints exist for codes, urls, markdown blobs, etc. and some types break down into multiple parts that the Java API consumes separately. We represent these using POJOs so we can control the contained data and expose it in a sane manner.
Here are two example classes: the model, and the abstracted primitive class.
@Data //lombok
class MyClass {
private String simplePrimitive;
private PrimitiveWrapper abstractedPrimitive;
}
@Data
class PrimitiveWrapper {
private String type;
private int version;
@JsonValue
@Override
public String toString() {
return String.format("%s|%d", type, version);
}
@JsonCreator
public static PrimitiveWrapper fromString(String stringValue) {
validateFormat(stringValue); //Abstracted for simplicity
String[] parts = stringValue.split("|");
return new PrimitiveWrapper(parts[0], Integer.parseInt(parts[1]));
}
}
When I do this, Swagger UI is showing an example JSON for MyClass that looks like:
{
"simplePrimitive": "string",
"abstractedPrimitive": {
"type": "string",
"version": 0
}
}
What it should look like is:
{
"simplePrimitive": "string",
"abstractedPrimitive": "string"
}
Or even better, the example could show the right pattern instead of just something generic like "string," but one problem at a time here :)
Workarounds found: Tweak the Docket of every service that uses the model (real deep sigh here):
new Docket(DocumentationType.SWAGGER_2)
.directModelSubstitute(PrimitiveWrapper.class, String.class)
...
Or, annotate every single instance of the wrapper within other models.
@Data //lombok
class MyClass {
private String simplePrimitive;
@ApiModelProperty(dataType = "java.lang.String"); //Workaround here
private PrimitiveWrapper abstractedPrimitive;
}
To reiterate though, I am looking for making every usage of the wrapper appear as a string without reconfiguring Docket (outside control of my library) and without annotating every usage (a maintenance problem).
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Auto-closing ignored issues seems like a questionable behavior. Even if the desire is for community to fix this, I at least need someone else to acknowledge that it's a problem. The core issue here is that Jackson models are being interpreted as types that are not the same serial format they represent
@BitFracture with over 700 issues, it is impossible for one person to triage and keep up. I have to be judicious about how I spend my time. There is always the option to reopen by just commenting your interest, so thank you for doing that. Also thank you for elaborating your exact need.
About this question. It is possible to override this behavior for parameters using @ApiImplicitParam(s), however it is does not extend to nested objects. @JsonValue is not directly supported, but for nested objects you could use alternate type rules as well, the caveat to doing that is it applies across the board. There is a feature request to allow it to do so selectively.
Also OpenAPI spec which I've been working on to try and release this following week has better support for this we can we can leverage.
Thanks for the response. Yeah, the use case I have, at least, is completely concerning nested fields. I am using some type overrides at the Docket level as I commented above with my other account. It does work, but requires each service to make the same customization. Possibly unrelated, but I notice the generated JSON examples are not customizable in this case as well. So I can't show a good example of an object that serializes with date or other formatting. Rather I'm limited to an example of "string." So these are things to think about. I appreciate you marking it as a feature request
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Bumping as still relevant
Relevant for me, too.