swagger-api / swagger-api/swagger-codegen-generators
Using Java Spring Server with oas2 doesn't compile due error in @ApiResponse annotation (content field not array)
Nobody has claimed this yet.
- Dominant language
- Mustache
- Stars
- 299
- Forks
- 439
- PR merge metrics
- No merged PRs in 30d
Description
How to reproduce
Using programmatically approach to create Java Spring Server with oas2 generates code:
new OpenApiGenerator(new v3.SpringCodegen() {
setJava8(true)
setInterfaceOnly(true)
setDateLibrary("java8")
// setUseOas2(false)
typeMapping.put("binary", "MultipartFile")
})
The generated API interface code looks like this:
package smsgw.api.openapi.generated.api;
import smsgw.api.openapi.generated.model.ArrayOfCodewordAvailableResponse;
import smsgw.api.openapi.generated.model.CodewordReservationResponse;
import smsgw.api.openapi.generated.model.CodewordReserve;
import smsgw.api.openapi.generated.model.InternalServerResponse;
import smsgw.api.openapi.generated.model.UnauthorizedResponse;
import smsgw.api.openapi.generated.model.ValidationResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.bind.annotation.CookieValue;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@javax.annotation.Generated(value = "SwaggerCodegenPluginX$$anon$3", date = "2022-03-13T23:19:15.833689+01:00[Europe/Oslo]")
@Validated
public interface CodewordApi {
Logger log = LoggerFactory.getLogger(CodewordApi.class);
default Optional<ObjectMapper> getObjectMapper(){
return Optional.empty();
}
default Optional<HttpServletRequest> getRequest(){
return Optional.empty();
}
default Optional<String> getAcceptHeader() {
return getRequest().map(r -> r.getHeader("Accept"));
}
@Operation(summary = "Check if codewords are available", description = "Check if codewords are available.", security = {
@SecurityRequirement(name = "tokenAuth") }, tags={ "Codeword" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "The availability of the codewords", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ArrayOfCodewordAvailableResponse.class))),
@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ValidationResponse.class))),
@ApiResponse(responseCode = "401", description = "Authentication error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UnauthorizedResponse.class))) })
@RequestMapping(value = "/codeword",
produces = { "application/json" },
method = RequestMethod.GET)
default ResponseEntity<ArrayOfCodewordAvailableResponse> availableCodeword(@NotNull @Size(min=1) @Parameter(in = ParameterIn.QUERY, description = "Comma seperated value (csv) list of codewords the organization wants to reserve. At least one codeword is required. Example: ?codeword=company,trademark " ,required=true,schema=@Schema()) @Valid @RequestParam(value = "codeword", required = true) List<String> codeword, @NotNull @Parameter(in = ParameterIn.QUERY, description = "Comma seperated value (csv) list of codewords the organization wants to reserve. At least one codeword is required. Example: ?moDestination=45345345 " ,required=true,schema=@Schema()) @Valid @RequestParam(value = "moDestination", required = true) String moDestination) {
// More generated code......
But the problem is that this code doesn't compile due to
@ApiResponse(content = @Content(mediaType = "application/json", schema = @Schema(implementation = UnauthorizedResponse.class))) }
Reason
The thing is that content is an array:
public @interface ApiResponse {
/**
* An array containing descriptions of potential response payloads, for different media types.
*
* @return array of content
**/
Content[] content() default {};
Solution
Adding brackets around the content solves the problem:
@ApiResponse(responseCode = "200", description = "The availability of the codewords", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ArrayOfCodewordAvailableResponse.class))}),
Fix
The problem can be fixed in src/main/resources/handlebars/JavaSpring/api.mustache
by changing the following line:
@ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}{{#baseType}}, content = {@Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class))}{{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class)))
Sidenote
For some reason it doesn't make any difference if setUseOas2() is true or false... It's expected that the problematic code should be ignored when useOas2=false due to {{^useOas2}}in the mustache file
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/main/resources/handlebars/JavaSpring/api.mustache and inspect the ApiResponse content generation shown in the issue. Regenerate a Java Spring server from an OAS2 definition using the programmatic setup, then confirm the generated annotations compile with content represented as an array.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100