OpenAPITools / OpenAPITools/openapi-generator

[BUG] [Spring] openapi-generator generates an incorrect stub for types named "List"

Open
#1,682 0 comments 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

Description

openapi-generator generates an incorrect spring stub for types named "List"

openapi-generator version

3.3.4

OpenAPI declaration file content or url

api.yaml

openapi: 3.0.0
info:
  title: Sample API
  description: API description in Markdown.
  version: 1.0.0
paths:
  /list:
    get:
      summary: Returns a list.
      description: Optional extended description in Markdown.
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "schema.json#/definitions/List"

schema.json

{
    "definitions": {
        "List": {
            "allOf": [
                {
                    "properties": {
                        "id": {
                            "type": "string"
                        }
                    }
                }
            ]
        }
    }
}
Command line used for generation
openapi-generator generate -g spring -i lapi.yaml -o generated -DdelegatePattern=true,hideGenerationTimestamp=true
Steps to reproduce

Invoke the command line above using the included api definitions.

Expected output

ListApi.java

/**
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (3.3.4).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */
package org.openapitools.api;

import org.openapitools.model.List;
import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
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;

import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.Map;

@Validated
@Api(value = "list", description = "the list API")
public interface ListApi {

    default ListApiDelegate getDelegate() {
        return new ListApiDelegate() {};
    }

    @ApiOperation(value = "Returns a list.", nickname = "listGet", notes = "Optional extended description in Markdown.", response = List.class, tags={  })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "OK", response = List.class) })
    @RequestMapping(value = "/list",
        produces = { "application/json" }, 
        method = RequestMethod.GET)
    default ResponseEntity<List> listGet() {
        return getDelegate().listGet();
    }

}

List.java

package org.openapitools.model;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.Valid;
import javax.validation.constraints.*;

/**
 * List
 */

public class List  {
  @JsonProperty("id")
  private String id;

  public List id(String id) {
    this.id = id;
    return this;
  }

  /**
   * Get id
   * @return id
  */
  @ApiModelProperty(value = "")


  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }


  @Override
  public boolean equals(java.lang.Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    List list = (List) o;
    return Objects.equals(this.id, list.id);
  }

  @Override
  public int hashCode() {
    return Objects.hash(id);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class List {\n");
    
    sb.append("    id: ").append(toIndentedString(id)).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(java.lang.Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }
}


Actual output
/**
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (3.3.4).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */
package org.openapitools.api;

import java.util.List;
import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
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;

import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;
import java.util.Map;

@Validated
@Api(value = "list", description = "the list API")
public interface ListApi {

    default ListApiDelegate getDelegate() {
        return new ListApiDelegate() {};
    }

    @ApiOperation(value = "Returns a list.", nickname = "listGet", notes = "Optional extended description in Markdown.", response = List.class, tags={  })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "OK", response = List.class) })
    @RequestMapping(value = "/list",
        produces = { "application/json" }, 
        method = RequestMethod.GET)
    default ResponseEntity<List> listGet() {
        return getDelegate().listGet();
    }

}

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 by running the provided openapi-generator command with api.yaml and schema.json, then compare the generated ListApi.java with the expected and actual output. Trace how the Spring generator resolves the model named List and its imports; done when the generated stub references the model without the conflicting java.util.List import.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, openapi, spring
Domain
api, backend-api-design
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.