OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.82k stars 6.58k forks source link

[BUG][Java][Spring] delegate pattern in combination with response wrapper generate code without delegate #17261

Open sasavilic opened 11 months ago

sasavilic commented 11 months ago

Bug Report Checklist

Description
openapi-generator version
  1. 6.6.0
  2. 7.1.0
  3. 7.2.0-SNAPSHOT
OpenAPI declaration file content or url
openapi: 3.0.3
info:
  title: Bug Report
  version: 1.0.0
servers:
  - url: /api/v1
paths:
  /bug:
    get:
      summary: Simple method
      operationId: getBug
      responses:
        200:
          description: "OK"
          content:
            'application/json':
              schema:
                type: string
Generation Details

Maven configuration

            <plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>7.1.0</version>
                <executions>
                    <execution>
                        <id>Generate sample</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <inputSpec>${project.basedir}/src/main/resources/spec/sample.yml</inputSpec>
                            <apiPackage>com.sample.rest</apiPackage>
                            <modelPackage>com.sample.rest</modelPackage>
                            <generatorName>spring</generatorName>
                            <configOptions>
                                <sourceFolder>java</sourceFolder>
                                <dateLibrary>java8</dateLibrary>
                                <interfaceOnly>true</interfaceOnly>
                                <delegatePattern>true</delegatePattern>
                                <responseWrapper>DeferredResult</responseWrapper>
                            </configOptions>
                            <library>spring-boot</library>
                            <output>${project.build.directory}/generated-sources/server</output>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
Steps to reproduce
  1. Generate code
  2. Correct code with delegate is expected, here is what I got:
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2023-11-30T11:16:24.335072+01:00[Europe/Vienna]")
@Validated
@Tag(name = "bug", description = "the bug API")
public interface BugApi {

    /**
     * GET /bug : Simple method
     *
     * @return OK (status code 200)
     */
    @Operation(
        operationId = "getBug",
        summary = "Simple method",
        responses = {
            @ApiResponse(responseCode = "200", description = "OK", content = {
                @Content(mediaType = "application/json", schema = @Schema(implementation = String.class))
            })
        }
    )
    @RequestMapping(
        method = RequestMethod.GET,
        value = "/bug",
        produces = { "application/json" }
    )

    org.springframework.web.context.request.async.DeferredResult<ResponseEntity<String>> _getBug(

    );
}

Expected result:

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2023-11-30T11:16:24.335072+01:00[Europe/Vienna]")
@Validated
@Tag(name = "bug", description = "the bug API")
public interface BugApi {

    /**
     * GET /bug : Simple method
     *
     * @return OK (status code 200)
     */
    @Operation(
        operationId = "getBug",
        summary = "Simple method",
        responses = {
            @ApiResponse(responseCode = "200", description = "OK", content = {
                @Content(mediaType = "application/json", schema = @Schema(implementation = String.class))
            })
        }
    )
    @RequestMapping(
        method = RequestMethod.GET,
        value = "/bug",
        produces = { "application/json" }
    )

    default org.springframework.web.context.request.async.DeferredResult<ResponseEntity<String>> _getBug() {
        return getBug();
    }

    default org.springframework.web.context.request.async.DeferredResult<ResponseEntity<String>> getBug() {
        org.springframework.web.context.request.async.DeferredResult<ResponseEntity<String>> result =
                new org.springframework.web.context.request.async.DeferredResult<ResponseEntity<String>>();
        result.setResult(ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build());
        return result;
    }
}
Related issues/PRs
Suggest a fix
AndresBena19 commented 2 months ago

I am having the same issue, when I use the responseWrapper in conjunction with the delegate pattern, the API generated does not add the default implementation and make the controller generate this error

method does not override or implement a method from a supertype.

Seems like the default is not added because of this conditional, so the controller layer is force to implemented the method but those method are not autogenerated to be compliant .

<configuration>
                            <generatorName>spring</generatorName>
                            <inputSpec>${project.basedir}/../agents-service-protocol/src/main/resources/openapi/xxxx-service.oas3.yaml</inputSpec>
                            <apiPackage>com.twilio.agents.service.server.api</apiPackage>
                            <modelPackage>com.twilio.agents.service.server.dtos</modelPackage>
                            <openapiNormalizer>REF_AS_PARENT_IN_ALLOF=true,REMOVE_ANYOF_ONEOF_AND_KEEP_PROPERTIES_ONLY=true,SIMPLIFY_ANYOF_STRING_AND_ENUM_STRING=true,SIMPLIFY_BOOLEAN_ENUM=true</openapiNormalizer>
                            <supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
                            <configOptions>
                                <sourceFolder>src/java/main</sourceFolder>
                                <oas3>true</oas3>
                                <dateLibrary>java8</dateLibrary>
                                <useSpringBoot3>true</useSpringBoot3>
                                <useJakartaEeValidation>true</useJakartaEeValidation>
                                <useSpringController>true</useSpringController>
                                <useBeanValidation>true</useBeanValidation>
                                <performBeanValidation>true</performBeanValidation>
                                <requestMappingMode>api_interface</requestMappingMode>
                                <useOptional>true</useOptional>
                                <handleApiException>true</handleApiException>
                                <openApiNullable>true</openApiNullable>
                                <skipDefaultInterface>false</skipDefaultInterface>
                                <responseWrapper>CompletableFuture</responseWrapper>
                                <useResponseEntity>true</useResponseEntity>
                                <useTags>true</useTags>
                                <modelPropertyNaming>original</modelPropertyNaming>
                                <delegatePattern>true</delegatePattern>
                                <generatedConstructorWithRequiredArgsOnly>true</generatedConstructorWithRequiredArgsOnly>
                                <additionalModelTypeAnnotations>@lombok.Data @lombok.Builder(setterPrefix = "with") @lombok.AllArgsConstructor</additionalModelTypeAnnotations>
                            </configOptions>
                            <typeMappings>
                                <typeMapping>OffsetDateTime=java.time.ZonedDateTime</typeMapping>
                            </typeMappings>
                        </configuration>