OpenAPITools / OpenAPITools/openapi-generator

[BUG] Migrating Swagger-code-gen to openapi-generator-maven-plugin with Mustache: Illegal start of expression ',', ')', or '[' expected

Open
#14,914 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

[Migrating Swagger-code-gen to openapi-generator-maven-plugin with Mustache: Illegal start of expression ',', ')', or '[' expected]

Console output:
Illegal start of expression ',', ')', or '[' expected

Description

I'm trying to migrate application with a several of other libaries from Java 11, Spring-Boot 2.7.x to Java 17, Spring-Boot 3 We also need to migrate swagger-codegen-maven-plugin to openapi-generator-maven-plugin, because we use .yaml files with Swagger specifications.
However, when we run a mvn clean package or mvn clean install, we are facing this issue: [Illegal start of expression ',', ')', or '' expected

We know that swagger-codegen-maven-plugin use the mustache file via tag, but openapi-generator-maven-plugin supports it either? With the same tag?
We notice yet that the comma are missing when the classes are generated, after the migration.

All swagger .yamls where converted from version 2.0 to version 3.0.1 via https://editor-next.swagger.io/

openapi-generator version

openapi-generator-maven-plugin 6.3.0

This is my pom.xml execution for the specified swagger file:
<execution>
    <id>crosscore</id>
    <goals>
        <goal>generate</goal>
    </goals>
    <configuration>
        <inputSpec>src/main/resources/feign/swagger/crosscore.yaml</inputSpec>
        <templateDirectory>src/main/resources/feign/templates</templateDirectory>
        <generatorName>spring</generatorName>
        <library>spring-cloud</library>
        <modelPackage>br.com.experian.api.crosscore.model</modelPackage>
        <apiPackage>br.com.experian.api.crosscore.api</apiPackage>
        <generateSupportingFiles>false</generateSupportingFiles>
        <configOptions>
            <sourceFolder>gen</sourceFolder>
            <useJakartaEe>true</useJakartaEe>
            <useSpringBoot3>true</useSpringBoot3>
            <java7>true</java7>
            <dateLibrary>joda</dateLibrary>
            <title>crosscore</title> <!-- Used for feign bean name and uri property-->
        </configOptions>
    </configuration>
</execution>
OpenAPI declaration file content or url
<execution>
    <id>crosscore</id>
    <goals>
        <goal>generate</goal>
    </goals>
    <configuration>
        <inputSpec>src/main/resources/feign/swagger/crosscore.yaml</inputSpec>
        <templateDirectory>src/main/resources/feign/templates</templateDirectory>
        <generatorName>spring</generatorName>
        <library>spring-cloud</library>
        <modelPackage>br.com.experian.api.crosscore.model</modelPackage>
        <apiPackage>br.com.experian.api.crosscore.api</apiPackage>
        <generateSupportingFiles>false</generateSupportingFiles>
        <configOptions>
            <sourceFolder>gen</sourceFolder>
            <useJakartaEe>true</useJakartaEe>
            <useSpringBoot3>true</useSpringBoot3>
            <java7>true</java7>
            <dateLibrary>joda</dateLibrary>
            <title>crosscore</title> <!-- Used for feign bean name and uri property-->
        </configOptions>
    </configuration>
</execution>
OpenAPI declaration file content or url
//more code ommited
paths:
  /DefaultRequestListener:
    post:
      tags:
        - CrossCore
      summary: CrossCore API Submit Request
      description: This API requires SSL, using the Security Certificate provided
        by Experian, and SHA-256 HMAC-signature using the HMAC key provided by Experian.
        Also, please inform the IP addresses to be allowed to connect to CrossCore.
      operationId: submit
      parameters:
        - name: workflow
          in: query
          description: ?RedBoxCPF
          schema:
            type: string
      requestBody:
        description: CrossCore Request
        content:
          application/json; charset=utf-8:
            schema:
              $ref: '#/components/schemas/RequestMessage'
        required: true
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResponseMessage'
      x-codegen-request-body-name: body
components:
  schemas:
    RequestMessage:
      required:
        - header
        - payload
      type: object
      properties:
        header:
          $ref: '#/components/schemas/RequestHeader'
        payload:
          $ref: '#/components/schemas/RequestPayload'
    RequestHeader:
      type: object
      properties:
        tenantId:
          maxLength: 8
          type: string
          description: Client Identifier as provided by Experian  Delivery Team.
          example: ABCD1234
        clientReferenceId:
          maxLength: 90
          type: string
          description: Unique client reference for each submission. This is provided
            by the client.
          example: YourRequestUniqueID
        messageTime:
          type: string
          description: Time message is submitted to the API, in UTC-0. The Time Zone
            Designator (TZD) value must be Z
          format: date-time
          example: 2019-10-23T14:20:04Z
        requestType:
          maxLength: 40
          type: string
          description: Used to determine the workflow and strategy manager as provided
            by Experian Delivery Team.
          example: KQO
        options:
          $ref: '#/components/schemas/Options'
        expRequestId:
          maxLength: 90
          type: string
          description: Experian generated unique Id
          example: RB000043766204
      description: Section for all control parameters for the submit API.
    Options:
      type: object
    RequestPayload:
      required:
        - application
        - contacts
      type: object
      properties:
        contacts:
          type: array
          description: The contacts object contains all contact information [Email(s)]
            for any email associated to an event. You can include any number of contacts'
            information in the message.
          items:
            $ref: '#/components/schemas/Contact'
        application:
          $ref: '#/components/schemas/Application'
        device:
          $ref: '#/components/schemas/Device'
    Contact:
      required:
        - emails
        - id
        - names
        - person
      type: object
      properties:
        id:
          maxLength: 40
          type: string
          description: Value used to cross-reference pieces of data to other objects
            within the message. When you need to reference this object, you will use
            this id value in the target object to associate this object to the target
            object
          example: MAINCONTACT_1
        person:
          $ref: '#/components/schemas/Person'
        names:
          $ref: '#/components/schemas/Names'
        emails:
          type: array
          items:
            $ref: '#/components/schemas/ContactEmail'
      description: The contacts object contains all contact information [Person(s),
        identityDocuments, organizations, addresses, telephones, etc.] for any person
        associated to an event. You can include any number of contacts' information
        in the message
    Person:
      required:
        - personIdentifier
        - typeOfPerson
      type: object
      properties:
        typeOfPerson:
          maxLength: 20
          type: string
          description: Indicator for the person type. Enum field values must be all
            CAPS. Please check the "Enum List" tab for a listing of all enumerations
          example: APPLICANT
          enum:
            - APPLICANT
        personIdentifier:
          maxLength: 20
          type: string
          description: Unique client identifier for the person. --Usar CPF do proponente--
          example: "12345678901"
      description: Single person defined for the submit request
    Names:
      type: object
      properties:
        id:
          type: string
          description: '...'
          example: MAINPERSONNAME_1
        firstName:
          type: string
          description: '...'
          example: JUSTINO
    ContactEmail:
      type: object
      properties:
        id:
          type: string
          description: '...'
          example: EMAIL_1
        email:
          type: string
          description: '...'
          format: email
          example: admin@nowhere.net
    Application:
      required:
        - applicants
      type: object
      properties:
        applicationId:
          maxLength: 26
          type: string
          description: ""
          example: APPLICATION_1
        applicants:
          type: array
          items:
            $ref: '#/components/schemas/Applicant'
    Applicant:
      type: object
      properties:
        id:
          maxLength: 40
          type: string
          description: ""
          example: MAINAPPLICANT_1
        applicantType:
          maxLength: 26
          type: string
          description: ""
          example: APPLICANT
          enum:
            - APPLICANT
        contactId:
          maxLength: 40
          type: string
          description: ""
          example: MAINCONTACT_1
        type:
          maxLength: 40
          type: string
          description: ""
          example: INDIVIDUAL
    Device:
      type: object
      properties:
        id:
          maxLength: 40
          type: string
          description: '...'
          example: DEVICEID_1
        ipAddress:
          maxLength: 40
          type: string
          description: '...'
          example: 10.0.0.1
    ResponseMessage:
      required:
        - clientResponsePayload
        - responseHeader
      type: object
      properties:
        responseHeader:
          $ref: '#/components/schemas/ResponseHeader'
        clientResponsePayload:
          $ref: '#/components/schemas/ClientResponsePayload'
        originalRequestData:
          $ref: '#/components/schemas/RequestPayload'
      description: Error, Warning, or Informational message describing the response.
  	//more code ommited
This is my mustache file
package {{package}};
{{#imports}}import {{import}};
{{/imports}}
{{#jdk8-no-delegate}}
import com.fasterxml.jackson.databind.ObjectMapper;
{{/jdk8-no-delegate}}
import io.swagger.annotations.*;
{{#jdk8-no-delegate}}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
{{/jdk8-no-delegate}}
import org.springframework.http.ResponseEntity;
{{#useBeanValidation}}
import org.springframework.validation.annotation.Validated;
{{/useBeanValidation}}
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;

{{#jdk8-no-delegate}}
import javax.servlet.http.HttpServletRequest;
{{/jdk8-no-delegate}}
{{#useBeanValidation}}
import javax.validation.Valid;
import javax.validation.constraints.*;
{{/useBeanValidation}}
{{#jdk8-no-delegate}}
import java.io.IOException;
{{/jdk8-no-delegate}}
import java.util.List;
{{#jdk8-no-delegate}}
import java.util.Optional;
{{/jdk8-no-delegate}}
{{^jdk8-no-delegate}}
    {{#useOptional}}
import java.util.Optional;
    {{/useOptional}}
{{/jdk8-no-delegate}}
{{#async}}
import java.util.concurrent.{{^jdk8}}Callable{{/jdk8}}{{#jdk8}}CompletableFuture{{/jdk8}};
{{/async}}

import io.swagger.annotations.*;
import org.springframework.cloud.openfeign.FeignClient;
import br.com.experian.configuration.feign.config.FeignClientConfig;

{{=<% %>=}}
@FeignClient(name="<%title%>", url="${api.<%title%>.uri}", configuration = FeignClientConfig.class)
<%={{ }}=%>
{{#operations}}
public interface {{classname}}Client {

{{#operation}}
    @RequestMapping(value = "{{{path}}}",{{#singleContentTypes}}{{#hasProduces}}
        produces = "{{{vendorExtensions.x-accepts}}};charset=UTF-8", {{/hasProduces}}{{#hasConsumes}}
        consumes = "{{{vendorExtensions.x-contentType}}};charset=UTF-8",{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}
        produces = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }, {{/hasProduces}}{{#hasConsumes}}
        consumes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} },{{/hasConsumes}}{{/singleContentTypes}}
        method = RequestMethod.{{httpMethod}})
    {{>returnTypes}} {{operationId}}(@RequestHeader(value = "hmac-signature") String authorization, {{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/allParams}});

{{/operation}}
}
{{/operations}}
Steps to reproduce

You have to run via mvn package/install the generate step of openapi-generator-maven-plugin, using a mustache template file.

This is my class generated via mvn clean package:

CrossCoreApiCliente

Related issues/PRs

I haven't found similar issues, but I asked at stack overflow: link

Suggest a fix

Debug and try to reproduce the step within a mustache template, and see how it deals with the multiple parameters, splited with a comma.

I don't know exactly why the guy who wrote this tried to do using mustache and swagger. Someone can help us? Thank you!

I'm expecting to understand if open-api-generator use the same tag for templates, and why we are facing a Illegal start of expression. Why is there a missing comma? Is this a bug of open-api-generator when using mustache templates?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the openapi-generator-maven-plugin 6.3.0 execution in the pom.xml and the referenced src/main/resources/feign/swagger/crosscore.yaml and templateDirectory. Compare the Mustache template assumptions with the generated classes and the reported missing commas or expression error. Done means reproducing the generation failure and documenting or testing the compatible template configuration.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, openapi
Domain
backend-api-design, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.