quarkus-openapi-generator icon indicating copy to clipboard operation
quarkus-openapi-generator copied to clipboard

Reactive server code generation fails

Open Ziaunys opened this issue 1 year ago • 3 comments

Hey there! I just started using this tool as a means to replace usage of the openapi-generator jax-rs server stub generator. This is necessary because I'd like my REST resources to be reactive. Unfortunately, I encountered an issue with generating the reactive interfaces that is hard to troubleshoot. The following contains, the OpenAPI spec in question, the properties set in my pom.xml , and the PROJECT_GENERATION_FAILED.txt output.

OpenAPI spec:

openapi: 3.0.3
info:
  contact:
    email: [email protected]
    name: Anon 
    url: 'https://anon.com'
  description: |-
    API for managing inventory sources and related metadata.

    Inventory is comprised of a collection of sources, which are used to generate a list of instances.
  title: Inventory
  version: '1.0'
  termsOfService: 'https://anon.com/legal'
servers:
  - url: 'http://localhost:9996/api/inventory'
tags:
  - name: Inventory
paths:
  '/v1/{org_id}/sources':
    parameters:
      - $ref: '#/components/parameters/OrgIdPathParam'
    get:
      summary: Get sources
      operationId: list-sources
      responses:
        '200':
          $ref: '#/components/responses/Sources'
      description: Return a list of all sources.
      tags:
        - Inventory
      security:
        - Auth0: []
  '/v1/{org_id}/sources/gcp':
    parameters:
      - $ref: '#/components/parameters/OrgIdPathParam'
    post:
      summary: Create or update source
      operationId: create-gcp-source
      responses:
        '200':
          description: OK
          headers: {}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Source'
      description: 'Create or update the source identified by a unique ID in the body, parsed by its source type (currently only accepts a service account key for GCP).'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateGCPSourceRequest'
        description: Upload JSON source credentials.
      parameters: []
      tags:
        - Inventory
      security:
        - Auth0: []
  '/v1/{org_id}/sources/gcp/{source_id}':
    parameters:
      - $ref: '#/components/parameters/OrgIdPathParam'
      - $ref: '#/components/parameters/SourceIdPathParam'
    put:
      summary: Put GCP Source
      operationId: put-gcp-source
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Source'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateGCPSourceRequest'
      tags:
        - Inventory
  '/v1/{org_id}/sources/{source_id}':
    parameters:
      - $ref: '#/components/parameters/OrgIdPathParam'
      - $ref: '#/components/parameters/SourceIdPathParam'
    delete:
      summary: Delete source
      operationId: delete-source
      responses:
        '204':
          description: No Content
        '404':
          description: Not Found
      tags:
        - Inventory
      security:
        - Auth0: []
    get:
      summary: Get Source
      operationId: getSource
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Source'
      security:
        - Auth0: []
      tags:
        - Inventory
  '/v1/{org_id}/sources/{source_id}:sync':
    post:
      operationId: sync-source
      responses:
        '200':
          description: OK
        '404':
          description: Not Found
      summary: Sync a source
      tags:
        - Inventory
      description: Synchronize available instances from the given source.
      security:
        - Auth0: []
    parameters:
      - $ref: '#/components/parameters/OrgIdPathParam'
      - $ref: '#/components/parameters/SourceIdPathParam'
  '/v1/{org_id}/search':
    parameters:
      - $ref: '#/components/parameters/OrgIdPathParam'
    post:
      summary: Search instances
      operationId: search-instances
      description: Search for instances based on a set of filters. Supports pagination based on instance ID cursor. Results are ordered by creation timestamp.
      parameters:
        - $ref: '#/components/parameters/PageOffsetQueryParam'
        - $ref: '#/components/parameters/PageSizeQueryParam'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaginatedSearchInstancesRequest'
            examples:
              match all:
                value:
                  filters: []
        description: Filter criteria.
      tags:
        - Inventory
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedSearchInstancesResponse'
        '400':
          description: Bad Request
      security:
        - Auth0: []
  '/v1/{org_id}/instance/{instance_id}':
    parameters:
      - $ref: '#/components/parameters/OrgIdPathParam'
      - $ref: '#/components/parameters/InstanceIdPathParam'
    get:
      summary: Get instance details
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Instance'
      operationId: get-instance
      description: Get instance details.
      tags:
        - Inventory
      security:
        - Auth0: []
  '/v1/{org_id}/instances/count':
    parameters:
      - schema:
          type: string
        name: org_id
        in: path
        required: true
    get:
      summary: Get Org Instance Count
      tags:
        - Inventory
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: integer
                format: int64
      operationId: get-org-instance-count
      description: Get the total number of instances in an organization
      security:
        - Auth0: []
components:
  parameters:
    OrgIdPathParam:
      name: org_id
      in: path
      required: true
      schema:
        type: string
      description: The tenant ID the resource belongs to
    PageOffsetQueryParam:
      name: page_offset
      in: query
      required: false
      schema:
        type: integer
      description: Token for the next page
    PageSizeQueryParam:
      name: page_size
      in: query
      required: false
      schema:
        type: integer
      description: Page size
    SourceIdPathParam:
      name: source_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: id of the source
    InstanceIdPathParam:
      name: instance_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: ID of the instance to retrieve
  requestBodies: {}
  schemas:
    Source:
      title: ''
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        last_synced:
          type: integer
          format: int64
        instance_count:
          type: integer
        credentials_id:
          type: string
          format: uuid
        type:
          $ref: '#/components/schemas/SourceType'
      required:
        - id
        - name
        - last_synced
        - instance_count
        - credentials_id
        - type
    SearchFilter:
      title: ''
      type: object
      properties:
        key:
          type: string
        operator:
          type: string
          enum:
            - lt
            - eq
            - gt
            - contains
            - not_contains
        value:
          type: string
        type:
          type: string
          enum:
            - GCP_METADATA
            - FACTS
            - SOURCE
            - ASSIGNED_POLICY
            - NODE
      required:
        - key
        - operator
        - value
        - type
    CuratedInstance:
      description: ''
      type: object
      title: ''
      properties:
        name:
          type: string
        id:
          type: string
        source:
          $ref: '#/components/schemas/Source'
        creation_time:
          type: integer
          format: int64
        internal_ip:
          type: string
        external_ip:
          type: string
        operating_system:
          type: string
        machine_type:
          type: string
        node_status:
          type: string
        uptime:
          type: integer
          format: int64
        zone:
          type: string
      required:
        - name
        - id
        - source
        - creation_time
        - internal_ip
        - external_ip
        - operating_system
        - machine_type
        - node_status
        - uptime
        - zone
    Instance:
      title: ''
      type: object
      properties:
        name:
          type: string
        source:
          $ref: '#/components/schemas/Source'
        facts:
          type: object
        metadata:
          type: object
      required:
        - name
        - source
        - facts
        - metadata
    GCPServiceAccount:
      title: GCPServiceAccount
      type: object
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
        project_id:
          type: string
        private_key_id:
          type: string
        private_key:
          type: string
        client_email:
          type: string
        client_id:
          type: string
        auth_uri:
          type: string
        token_uri:
          type: string
        auth_provider_x509_cert_url:
          type: string
        client_x509_cert_url:
          type: string
      required:
        - id
        - type
        - project_id
        - private_key_id
        - private_key
        - client_email
        - client_id
        - auth_uri
        - token_uri
        - auth_provider_x509_cert_url
        - client_x509_cert_url
    CreateGCPSourceRequest:
      title: CreateGCPSourceRequest
      type: object
      properties:
        name:
          type: string
        gather_facts_on_ingest:
          type: boolean
          default: true
        credentials:
          $ref: '#/components/schemas/GCPCredential'
      required:
        - name
        - gather_facts_on_ingest
        - credentials
    PatchGCPSourceRequest:
      title: PatchGCPSourceRequest
      type: object
      properties:
        name:
          type: string
        gather_facts_on_ingest:
          type: boolean
    PaginatedSearchInstancesRequest:
      title: PaginatedSearchInstancesRequest
      type: object
      properties:
        filters:
          type: array
          items:
            $ref: '#/components/schemas/SearchFilter'
    PaginatedSearchInstancesResponse:
      title: PaginatedSearchInstancesResponse
      type: object
      properties:
        next_page_offset:
          type: integer
        instances:
          type: array
          items:
            $ref: '#/components/schemas/CuratedInstance'
        total_count:
          type: integer
          format: int64
      required:
        - next_page_offset
        - instances
        - total_count
    GCPCredential:
      title: GCPCredential
      type: object
      properties:
        type:
          type: string
        project_id:
          type: string
        private_key_id:
          type: string
        private_key:
          type: string
        client_email:
          type: string
        client_id:
          type: string
        auth_uri:
          type: string
        token_uri:
          type: string
        auth_provider_x509_cert_url:
          type: string
        client_x509_cert_url:
          type: string
      required:
        - type
        - project_id
        - private_key_id
        - private_key
        - client_email
        - client_id
        - auth_uri
        - token_uri
        - auth_provider_x509_cert_url
        - client_x509_cert_url
    SourceType:
      type: string
      title: SourceType
      enum:
        - GCP
  responses:
    Sources:
      description: A list of sources
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: '#/components/schemas/Source'
    Search:
      description: 'A list of curated instance details matching the search criteria, with a next cursor if there are more results.'
      content:
        application/json:
          schema:
            type: object
            properties:
              next_cursor:
                type: string
              instances:
                type: array
                items:
                  $ref: '#/components/schemas/CuratedInstance'
            required:
              - instances
  securitySchemes:
    Auth0:
      type: http
      scheme: bearer
      bearerFormat: jwt
      description: Auth0 token

My pom.xml properties:

        <quarkus.openapi.generator.spec>openapi.yaml</quarkus.openapi.generator.spec>
        <quarkus.openapi.generator.base-package>com.anon.web.api</quarkus.openapi.generator.base-package>
        <quarkus.openapi.generator.reactive>true</quarkus.openapi.generator.reactive>

quarkus-openapi-generator version: 3.0.0-snapshot built from main

Error:

An unexpected server error was encountered while generating the project.  See
the details of the error below.

Generation Log:

Generating Bean: com.anon.web.api.beans.Source
Generating Bean: com.anon.web.api.beans.SearchFilter
Generating Bean: com.anon.web.api.beans.CuratedInstance
Generating Bean: com.anon.web.api.beans.Instance
Generating Bean: com.anon.web.api.beans.GCPServiceAccount
Generating Bean: com.anon.web.api.beans.CreateGCPSourceRequest
Generating Bean: com.anon.web.api.beans.PatchGCPSourceRequest
Generating Bean: com.anon.web.api.beans.PaginatedSearchInstancesRequest
Generating Bean: com.anon.web.api.beans.PaginatedSearchInstancesResponse
Generating Bean: com.anon.web.api.beans.GCPCredential
Generating Bean: com.anon.web.api.beans.SourceType
Adding to zip: com/anon/web/api/beans/Source.java
Adding to zip: com/anon/web/api/beans/PaginatedSearchInstancesRequest.java
Adding to zip: com/anon/web/api/beans/Facts.java
Adding to zip: com/anon/web/api/beans/CreateGCPSourceRequest.java
Adding to zip: com/anon/web/api/beans/SourceType.java
Adding to zip: com/anon/web/api/beans/PatchGCPSourceRequest.java
Adding to zip: com/anon/web/api/beans/Metadata.java
Adding to zip: com/anon/web/api/beans/CuratedInstance.java
Adding to zip: com/anon/web/api/beans/PaginatedSearchInstancesResponse.java
Adding to zip: com/anon/web/api/beans/Instance.java
Adding to zip: com/anon/web/api/beans/GCPCredential.java
Adding to zip: com/anon/web/api/beans/SearchFilter.java
Adding to zip: com/anon/web/api/beans/GCPServiceAccount.java
Generating Interface: com.anon.web.api.V1Resource


Server Stack Trace:
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
	at java.base/java.util.Objects.checkIndex(Objects.java:361)
	at java.base/java.util.ArrayList.get(ArrayList.java:427)
	at java.base/java.util.Collections$UnmodifiableList.get(Collections.java:1347)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.lambda$parseType$15(OpenApi2JaxRs.java:657)
	at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1220)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.parseType(OpenApi2JaxRs.java:654)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.generateReactiveTypeName(OpenApi2JaxRs.java:769)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.lambda$generateJavaInterface$9(OpenApi2JaxRs.java:560)
	at java.base/java.util.Optional.map(Optional.java:260)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.lambda$generateJavaInterface$14(OpenApi2JaxRs.java:560)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.generateJavaInterface(OpenApi2JaxRs.java:519)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.generateJavaInterface(OpenApi2JaxRs.java:634)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.generateAll(OpenApi2JaxRs.java:322)
	at io.apicurio.hub.api.codegen.OpenApi2JaxRs.generate(OpenApi2JaxRs.java:216)
	at io.quarkiverse.openapi.server.generator.deployment.codegen.ApicurioCodegenWrapper.generate(ApicurioCodegenWrapper.java:69)
	at io.quarkiverse.openapi.server.generator.deployment.codegen.ApicurioOpenApiServerCodegen.trigger(ApicurioOpenApiServerCodegen.java:87)
	at io.quarkus.deployment.CodeGenerator.lambda$trigger$4(CodeGenerator.java:206)
	at io.quarkus.deployment.CodeGenerator.callWithClassloader(CodeGenerator.java:181)
	at io.quarkus.deployment.CodeGenerator.trigger(CodeGenerator.java:203)
	at io.quarkus.deployment.CodeGenerator.initAndRun(CodeGenerator.java:80)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at io.quarkus.maven.GenerateCodeMojo.generateCode(GenerateCodeMojo.java:88)
	at io.quarkus.maven.GenerateCodeMojo.doExecute(GenerateCodeMojo.java:54)
	at io.quarkus.maven.QuarkusBootstrapMojo.execute(QuarkusBootstrapMojo.java:171)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:126)
	at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2(MojoExecutor.java:328)
	at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute(MojoExecutor.java:316)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:174)
	at org.apache.maven.lifecycle.internal.MojoExecutor.access$000(MojoExecutor.java:75)
	at org.apache.maven.lifecycle.internal.MojoExecutor$1.run(MojoExecutor.java:162)
	at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute(DefaultMojosExecutionStrategy.java:39)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:159)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:105)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:73)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:53)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:118)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:261)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:173)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:101)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:903)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:280)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:203)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:255)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:201)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:361)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:314)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at org.apache.maven.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:52)
	at org.apache.maven.wrapper.WrapperExecutor.execute(WrapperExecutor.java:161)
	at org.apache.maven.wrapper.MavenWrapperMain.main(MavenWrapperMain.java:73)

Ziaunys avatar Sep 18 '24 19:09 Ziaunys

@ricardozanini @hbelmiro This is being labeled as Stale.

github-actions[bot] avatar Nov 19 '24 12:11 github-actions[bot]

@carlesarnal can you please take a look?

ricardozanini avatar Nov 21 '24 15:11 ricardozanini

@ricardozanini @hbelmiro This is being labeled as Stale.

github-actions[bot] avatar Jan 21 '25 12:01 github-actions[bot]

Closed by https://github.com/quarkiverse/quarkus-openapi-generator/pull/1015 (waiting new release)

mcruzdev avatar Mar 21 '25 15:03 mcruzdev