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

Nullable enum in query string does not generate compilable code #936

Open
brice-laurencin opened this issue Jan 10, 2025 · 5 comments
Open

Comments

@brice-laurencin
Copy link
Contributor

If the parameter is defined as @QueryParam("status") status: StatusEnum
the OAS is as such:

- name: status
  in: query
  required: true
  schema:
    $ref: "#/components/schemas/StatusEnum"

And the generated param is @io.quarkiverse.openapi.generator.annotations.GeneratedParam("source") @jakarta.ws.rs.QueryParam("source") EnumType source

If the parameter is defined as @QueryParam("status") status: StatusEnum?

the OAS is as such:

- name: status
  in: query
  required: true
  schema:
    allOf:
      - $ref: "#/components/schemas/StatusEnum"
      - nullable: true

And the generated param is:
@io.quarkiverse.openapi.generator.annotations.GeneratedParam("source") @jakarta.ws.rs.BeanParam EnumType.EnumTypeQueryParam source

Here, it does not compile because EnumType.EnumTypeQueryParam is not generated.

Here is a complete yaml exposing the issue:

openapi: 3.0.3
info:
  title: echo
  version: '1.0.0'
  description: ""
paths:
  /ko:
    post:
      summary: Echo
      operationId: postKo
      parameters:
        - name: source
          in: query
          description: enum value
          required: false
          schema:
            allOf:
              - $ref: "#/components/schemas/EnumType"
              - nullable: true

      responses:
        "200":
          description: OK
  /ok:
    post:
      summary: Echo
      operationId: postOk
      parameters:
        - name: source
          in: query
          description: enum value
          required: false
          schema:
            $ref: "#/components/schemas/EnumType"


      responses:
        "200":
          description: OK

components:
  schemas:
    EnumType:
      enum:
        - SOMETHING
        - ELSE
      type: string

I tried to wrap my head around this, maybe generate a QueryParam class for the enum, but I failed to make sense of it. The enum is just the enum, the QueryParam class is here to explode members of actual classes.

The example yaml is generated from a quarkus project, and I feel the issue could be there and the schema is incorrect.
So I'm unsure this report is valid.

@ricardozanini
Copy link
Member

What's the impact of:

@io.quarkiverse.openapi.generator.annotations.GeneratedParam("source") @jakarta.ws.rs.QueryParam("source") EnumType source

Being null?

@brice-laurencin
Copy link
Contributor Author

not sure I understand the question, but:
in the generated code: it tries to parse the parameter value with EnumType.EnumTypeQueryParam
in the service code, this is business logic I suppose. The controller would handle the query any way it sees fit.

@ricardozanini
Copy link
Member

I must run this locally actually to see what's happening. Based on your description, I'm unsure if I'm following what's happening. Maybe my old brain is getting rusty. 😅

@brice-laurencin
Copy link
Contributor Author

brice-laurencin commented Jan 16, 2025

sorry.
I get that the OAS alone can be hard to read. I for one cannot read the matrix 😅

Here is some code with:

  • a quarkus service in the root
  • a client generated in clients/jvm
  • you can have the client built with ./gradlew :clients:jvm:build
  • you can then find the client generated code in clients/jvm/build/classes/java/quarkus-generated-sources/open-api-json/care/resilience/patientservice/client/api/GreetingResourceApi.java

We end up with 2 methods for the client (simplified here):

    public io.smallrye.mutiny.Uni<String> helloGet(@jakarta.ws.rs.BeanParam Fred.FredQueryParam fred
    );

    public io.smallrye.mutiny.Uni<String> hiGet(@jakarta.ws.rs.QueryParam("fred") Fred fred
    );

hiGet is mapping to the service method with the non-nullable enum query param
helloGet maps to the nullable one.

helloGet wants a Fred.FredQueryParam attribute, as a BeanParam, where hiGet wants a Fred QueryParam, which is what I'd actually expect, even for a nullable enum. Or so I think, please tell me if I'm wrong.

This class is not generated in the Fred enum:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;


/**
 * Gets or Sets Fred
 */
@com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)
public enum Fred {
/**
 * Special value if the API response contains some new value not declared in this enum.
 * You should react accordingly.
 */
UNEXPECTED(String.valueOf("unexpected")),
    BOB(String.valueOf("BOB"));

    // caching enum access
    private static final java.util.EnumSet<Fred> values = java.util.EnumSet.allOf(Fred.class);

    private String value;

    Fred(String value){
        this.value = value;
    }

    @com.fasterxml.jackson.annotation.JsonValue
    public String value() {
        return value;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }

    @com.fasterxml.jackson.annotation.JsonCreator
    public static Fred fromString(String text) {
        for (Fred b : values) {
            if (String.valueOf(b.value).equalsIgnoreCase(text)) {
                return b;
            }
        }
        return UNEXPECTED;
    }
}

If Fred was a Pojo instead of an enum, I'd have a XQueryParam class generated alongside the Pojo.

Thanks for your help!

@ricardozanini
Copy link
Member

Yes, I think it's a bug. To me, Fred enum should be a valid entry, even if nullable. I can't see why not. @hbelmiro @mcruzdev any thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants