Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reactive server code generation fails #803

Open
Ziaunys opened this issue Sep 18, 2024 · 2 comments
Open

Reactive server code generation fails #803

Ziaunys opened this issue Sep 18, 2024 · 2 comments
Assignees
Labels
area:server This item is related to the server extension

Comments

@Ziaunys
Copy link

Ziaunys commented Sep 18, 2024

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)

@ricardozanini ricardozanini added the area:server This item is related to the server extension label Sep 19, 2024
Copy link
Contributor

@ricardozanini @hbelmiro This is being labeled as Stale.

@github-actions github-actions bot added the Stale label Nov 19, 2024
@ricardozanini
Copy link
Member

@carlesarnal can you please take a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:server This item is related to the server extension
Projects
None yet
Development

No branches or pull requests

3 participants