Created by: ruedigerk
This PR adds the option "useTypesafeResponses" to the jaxrs-spec generator, that when used together with the "interfaceOnly" option, generates an operation-specific response class for each operation. This forces the implementer of the interfaces to return responses that are in accordance with the contract while preserving the ability to return any of the combinations of status code and content type defined in the contract.
Without this new option, one is limited to one of two options, both lacking in the eyes of this author. One is to use the "returnResponses=true" style, which enables returning every status code/content type combination actually defined in the contract, while giving no assistance nor validation to only return what is in accordance with the contract. Or one can use the "returnResponses=false" style, where one can only return response entities in accordance with the contract, but is forced to return the same "generator selected" combination of status code/content type regardless of the combinations defined in the contract.
An example of the generated code looks like this, with the operation-specific response class FindPetsByTagsResponse based on the response wrapper class ResponseWrapper that is generated once for the whole API:
First the responses section of the contract the example is based on:
responses:
'200':
description: successful operation
content:
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'204':
description: successful operation, but nothing found
'400':
description: Invalid parameters
Here the code generated for the example above:
@GET
@Path("/findByTags")
@Produces({ "application/xml", "application/json" })
FindPetsByTagsResponse findPetsByTags(@QueryParam("tags") @NotNull List<String> tags);
public static class FindPetsByTagsResponse extends org.openapitools.api.support.ResponseWrapper {
private FindPetsByTagsResponse(Response delegate) {
super(delegate);
}
public static FindPetsByTagsResponse with200ApplicationXml(List<Pet> entity) {
return new FindPetsByTagsResponse(Response.status(200).header("Content-Type", "application/xml").entity(entity).build());
}
public static FindPetsByTagsResponse with200ApplicationJson(List<Pet> entity) {
return new FindPetsByTagsResponse(Response.status(200).header("Content-Type", "application/json").entity(entity).build());
}
public static FindPetsByTagsResponse with204() {
return new FindPetsByTagsResponse(Response.status(204).build());
}
public static FindPetsByTagsResponse with400() {
return new FindPetsByTagsResponse(Response.status(400).build());
}
public static FindPetsByTagsResponse withCustomResponse(Response response) {
return new FindPetsByTagsResponse(response);
}
}
The "withCustomResponse" method is generated for special circumstances where one needs to define additional properties of the response. This is rarely used but still necessary in the code bases of the company I work in, where we already use a code generation scheme as proposed by this PR.
Fixes #7099.
Please review.
@bbdouglas (2017/07) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01) @karismann (2019/03) @Zomzog (2019/04) @lwlee2608 (2019/10) @bkabrda (2020/01)
PR checklist
-
Read the contribution guidelines. -
If contributing template-only or documentation-only changes which will change sample output, build the project beforehand. -
Run the shell script ./bin/generate-samples.sh
to update all Petstore samples related to your fix. This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master. These must match the expectations made by your contribution. You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example./bin/generate-samples.sh bin/configs/java*
. For Windows users, please run the script in Git BASH. -
File the PR against the correct branch: master
-
Copy the technical committee to review the pull request if your PR is targeting a particular programming language.