Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate Swagger codegen Java models as JPA Entities

I am using Swagger codegen to create Java models to be used in a Spring REST server, and would like to know how to get Swagger to declare each model as a JPA entity.

I generate the code with the swagger-codegen-maven-plugin as follows:

<plugin>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-codegen-maven-plugin</artifactId>
    <version>2.4.0</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/openApi/Rack.json</inputSpec>
                <language>spring</language>
                <groupId>com.me</groupId>
                <artifactId>rest-server</artifactId>
                <apiPackage>com.me.rest.api</apiPackage>
                <modelPackage>com.me.rest.model</modelPackage>
                <invokerPackage>com.me.rest.invoker</invokerPackage>
                <configOptions>
                    <sourceFolder>src/gen/java/main</sourceFolder>
                    <java8>true</java8>
                    <dateLibrary>java8</dateLibrary>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>

As I have it now, this is the abbreviated java code that gets generated:

@Validated
@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "...")

public class Rack   {
  @JsonProperty("id")
  private Long id = null;

  @JsonProperty("name")
  private String name = null;

  ...
}

How do I get Swagger to add the @Entity and @Id JPA annotations, as follows?

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Validated
@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "...")

public class Rack   {
  @Id
  @JsonProperty("id")
  private Long id = null;

  @JsonProperty("name")
  private String name = null;

  ...
}

This way, all I would have to do to get Spring to automatically expose these generated classes as REST APIs, would be to add the following to my pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

Then I could create the JPA repositories with Spring-Data, as follows:

public interface RackRepository extends CrudRepository<Rack, Long> {
}
like image 777
Brady Avatar asked Feb 05 '19 14:02

Brady


People also ask

What is swagger codegen?

Swagger Codegen is an open source project which allows generation of API client libraries (SDK generation), server stubs, and documentation automatically from an OpenAPI Specification.


Video Answer


3 Answers

While the right way to solve this surely is an extension of swagger-codegen (probably with the introduction of some kind of include/exclude config), I got away with a fairly simply post-processing of the generated files.

In contrast to the OP I use Gradle instead of Maven and leveraged its extended filtering functionality. For Maven it is probably necessary to run a Groovy-script by way of the Groovy-Maven-Plugin, since Maven only supports placeholder substitution (as does Ant, so using the AntRun-Plugin would also not work).

I used a simple heuristic to only include entities with an id - the logic is as follows:

  • for all Java-files containing an ID-field
    • include import statement for javax.persistence.* after the package declaration
    • add the @Entity-annotation before the class definition
    • for the ID-field, add the annotations @Id and @GeneratedValue
    • (based on field names, other annotations - @OneToMany etc. - may be added as well)

Gradle-users may find the following task useful as a start:

task generateJpaAnnotations(type: Copy) {
    from "${swaggerSources.<modelName>.code.outputDir}/src/main/java"
    into "<output dir>
    include '**/*.java'

    eachFile {
        if (it.file.text.contains("private Long id")) {
            filter { line -> line.contains('package') ? "$line\nimport javax.persistence.*;" : line }
            filter { line -> line.contains('public class') ? "@Entity\n$line" : line }
            filter { line -> line.contains('private Long id') ? "@Id\n@GeneratedValue(strategy=GenerationType.AUTO)\n$line" : line }        }
    }
}
like image 59
mthomas Avatar answered Nov 17 '22 04:11

mthomas


A PR has recently been merged fixing your issue : https://github.com/OpenAPITools/openapi-generator/pull/11775

You need to upgrade your Maven plugin to use the latest version (currently unreleased, only snapshot is available)

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>6.0.0-SNAPSHOT</version>
    ...
</plugin>

The configuration might be slightly different.

Then you need to add x-class-extra-annotation and x-field-extra-annotation in your spec.

For instance for the Pet Clinic:

  schemas:
    Pet:
      type: object
      x-class-extra-annotation: "@javax.persistence.Entity"
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
          x-field-extra-annotation: "@javax.persistence.Id"
        name:
          type: string
        tag:
          type: string
like image 34
Mathieu D Avatar answered Nov 17 '22 05:11

Mathieu D


So I'm actually asking myself the same question. I found an example but the guy is simply re-defining his POJOs and providing a way to adapt the generated ones to the handwritten ones. Tedious and not evolutive.

Globally this could be hard because I'm not sure there is a way in your swagger to decide which POJO will be JPA enabled and maybe you don't want them all in your DB (?) Also, how to you tag the id in swagger? If you know of such a way, you can always modify the mustache (pojo.mustache I guess) to give you the annotations you're missing.

like image 39
Kiskit Avatar answered Nov 17 '22 04:11

Kiskit