OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.82k stars 6.58k forks source link

[REQ] Extend Spring generator to support JPA annotations and spring-data-jpa #2972

Closed InfoSec812 closed 4 years ago

InfoSec812 commented 5 years ago

Is your feature request related to a problem? Please describe.

Describe the solution you'd like

I will be submitting a PR with the appropriate changes, but in general, parsing something like this in an object definition

components:
  schemas:
    EventBase:
      title: Root Type for Event
      description: The root of the Event type's schema.
      x-jpa-table-name: events
      required:
        - eventType
        - id
        - name
        - startTime
        - endTime
      type: object
      discriminator:
        propertyName: eventType
      properties:
        eventType:
          type: string
        name:
          type: string
        id:
          format: uuid
          type: string
          uniqueItems: true
          x-jpa-id: true
        startTime:
          format: date-time
          type: string
          x-jpa-column-name: start_time
        endTime:
          format: date-time
          type: string
          x-jpa-column-name: end_time
        duration:
          format: string
          x-jpa-transient: true
        description:
          type: string
        personnel:
          type: array
          items: {}

Into something like this:

@Entity
@Table(name = "events")
public class EventBase {
  @JsonProperty("eventType")
  @NonNull
  private String eventType;

  @JsonProperty("name")
  @NonNull
  private String name;

  @JsonProperty("id")
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "event_seq")
  private Integer id;

  @JsonProperty("startTime")
  @NonNull
  private OffsetDateTime startTime;

  @JsonProperty("endTime")
  @NonNull
  private OffsetDateTime endTime;

  @JsonProperty("duration")
  @Transient
  private Duration duration;

  @JsonProperty("description")
  private String description;

  @JsonProperty("personnel")
  private List<Object> personnel = null;

  public EventBase eventType(String eventType) {
    this.eventType = eventType;
    return this;
  }

  /**
   * Get eventType
   * @return eventType
  */
  @ApiModelProperty(required = true, value = "")
  public String getEventType() {
    return eventType;
  }

  public void setEventType(String eventType) {
    this.eventType = eventType;
  }

  public EventBase name(String name) {
    this.name = name;
    return this;
  }

  /**
   * Get name
   * @return name
  */
  @ApiModelProperty(required = true, value = "")
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public EventBase id(Integer id) {
    this.id = id;
    return this;
  }

  /**
   * Get id
   * @return id
  */
  @ApiModelProperty(required = true, value = "")
  public Integer getId() {
    return id;
  }

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

  public EventBase startTime(OffsetDateTime startTime) {
    this.startTime = startTime;
    return this;
  }

  /**
   * Get startTime
   * @return startTime
  */
  @ApiModelProperty(required = true, value = "")
  public OffsetDateTime getStartTime() {
    return startTime;
  }

  public void setStartTime(OffsetDateTime startTime) {
    this.startTime = startTime;
  }

  public EventBase endTime(OffsetDateTime endTime) {
    this.endTime = endTime;
    return this;
  }

  /**
   * Get endTime
   * @return endTime
  */
  @ApiModelProperty(required = true, value = "")
  public OffsetDateTime getEndTime() {
    return endTime;
  }

  public void setEndTime(OffsetDateTime endTime) {
    this.endTime = endTime;
  }

  public EventBase description(String description) {
    this.description = description;
    return this;
  }

  /**
   * Get description
   * @return description
  */
  @ApiModelProperty(value = "")
  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public EventBase personnel(List<Object> personnel) {
    this.personnel = personnel;
    return this;
  }

  public EventBase addPersonnelItem(Object personnelItem) {
    if (this.personnel == null) {
      this.personnel = new ArrayList<>();
    }
    this.personnel.add(personnelItem);
    return this;
  }

  /**
   * Get personnel
   * @return personnel
  */
  @ApiModelProperty(value = "")
  public List<Object> getPersonnel() {
    return personnel;
  }

  public void setPersonnel(List<Object> personnel) {
    this.personnel = personnel;
  }

  @Override
  public boolean equals(java.lang.Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    EventBase eventBase = (EventBase) o;
    return Objects.equals(this.eventType, eventBase.eventType) &&
        Objects.equals(this.name, eventBase.name) &&
        Objects.equals(this.id, eventBase.id) &&
        Objects.equals(this.startTime, eventBase.startTime) &&
        Objects.equals(this.endTime, eventBase.endTime) &&
        Objects.equals(this.description, eventBase.description) &&
        Objects.equals(this.personnel, eventBase.personnel);
  }

  @Override
  public int hashCode() {
    return Objects.hash(eventType, name, id, startTime, endTime, description, personnel);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class EventBase {\n");

    sb.append("    eventType: ").append(toIndentedString(eventType)).append("\n");
    sb.append("    name: ").append(toIndentedString(name)).append("\n");
    sb.append("    id: ").append(toIndentedString(id)).append("\n");
    sb.append("    startTime: ").append(toIndentedString(startTime)).append("\n");
    sb.append("    endTime: ").append(toIndentedString(endTime)).append("\n");
    sb.append("    description: ").append(toIndentedString(description)).append("\n");
    sb.append("    personnel: ").append(toIndentedString(personnel)).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    ");
  }
}

Describe alternatives you've considered

I have considered using a post-processor script, but it is not as reliable in a CI/CD environment and could be difficult to make cross-platform.

InfoSec812 commented 5 years ago

Also, something like x-jpa-additional-imports as an array? Something like:

components:
  schemas:
    EventBase:
      title: Root Type for Event
      description: The root of the Event type's schema.
      x-jpa-table-name: events
      x-jpa-additional-imports:
        - javax.persistence.GeneratedValue
        - javax.persistence.GenerationType
        - javax.persistence.Embeddable
        - javax.persistence.MappedSuperclass
        - javax.persistence.Enumerated
      required:
        - eventType
        - id
        - name
        - startTime
        - endTime
      type: object
InfoSec812 commented 5 years ago

Looping in @haithamshahin333

InfoSec812 commented 5 years ago

And also, to improve flexibility and extensibility, on the field definitions we could do:

      properties:
        eventType:
          type: string
        name:
          type: string
        id:
          format: uuid
          type: string
          uniqueItems: true
          x-jpa-annotations:
            - @Id
            - @GeneratedValue(strategy = GeneratedValue.SEQUENCE, generator = "events_seq")
            - @Column(name = "event_id")
macjohnny commented 5 years ago

sounds good

MarkusBansky commented 4 years ago

Proposed extension on #5312

InfoSec812 commented 4 years ago

The more I dig into this, the more I am convinced that this needs to be a broader effort which modernizes/updates all of the Java based generators, including JAX-RS. I'm going to close this issue and consider doing some work toward that end.