Swagger not scanning ApiModel and ApiModelProperty annotations in entity classes that are in a different jar file
Asked Answered
T

2

5

I have the following two entity classes.

The first class is SampleApiEntity:

package my.company.rest;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.hibernate.annotations.Type;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@ApiModel (
    value       = "SampleApiEntity",
    description = "This is a sample entity from the Api package."
)
@Entity
public class SampleApiEntity
        implements Serializable
{
    public SampleApiEntity () {}

    private static final long serialVersionUID = 1L;

    @Column (nullable = false)
    @ApiModelProperty (
        value    = "level",
        required = true
    )
    private Integer   level;

    @Column (length = 255)
    @ApiModelProperty (
        value    = "description"
    )
    private String    description;

    @Column (nullable = false)
    @ApiModelProperty (
        value    = "time",
        required = true
    )
    private Timestamp time;

    @Id
    @Column (
        unique   = true,
        nullable = false
    )
    @Type (type = "pg-uuid")
    @ApiModelProperty (
        value    = "id",
        readOnly = true,
        dataType = "uuid",
        example  = "123e4567-e89b-12d3-a456-426655440000"
    )
    private UUID      sampleApiEntityId;

    public String getDescription ()
    {
        return this.description;
    }

    public Integer getLevel ()
    {
        return this.level;
    }

    public UUID getSampleApiEntityId ()
    {
        return this.sampleApiEntityId;
    }

    public Timestamp getTime ()
    {
        return this.time;
    }

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

    public void setLevel (Integer level)
    {
        this.level = level;
    }

    public void setSampleApiEntityId (UUID sampleApiEntityId)
    {
        this.sampleApiEntityId = sampleApiEntityId;
    }

    public void setTime (Timestamp time)
    {
        this.time = time;
    }
}

The second class is SampleModelEntity:

package my.company.model;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.hibernate.annotations.Type;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@ApiModel (
    value       = "SampleModelEntity",
    description = "This is a sample entity from the Model package."
)
@Entity
public class SampleModelEntity
        implements Serializable
{
    public SampleModelEntity () {}

    private static final long serialVersionUID = 1L;

    @Column (nullable = false)
    @ApiModelProperty (
        value    = "level",
        required = true
    )
    private Integer   level;

    @Column (length = 255)
    @ApiModelProperty (
        value    = "description"
    )
    private String    description;

    @Column (nullable = false)
    @ApiModelProperty (
        value    = "time",
        required = true
    )
    private Timestamp time;

    @Id
    @Column (
        unique   = true,
        nullable = false
    )
    @Type (type = "pg-uuid")
    @ApiModelProperty (
        value    = "id",
        readOnly = true,
        example  = "123e4567-e89b-12d3-a456-426655440000"
    )
    private UUID      sampleModelEntityId;

    public String getDescription ()
    {
        return this.description;
    }

    public Integer getLevel ()
    {
        return this.level;
    }

    public UUID getSampleModelEntityId ()
    {
        return this.sampleModelEntityId;
    }

    public Timestamp getTime ()
    {
        return this.time;
    }

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

    public void setLevel (Integer level)
    {
        this.level = level;
    }

    public void setSampleModelEntityId (UUID sampleModelEntityId)
    {
        this.sampleModelEntityId = sampleModelEntityId;
    }

    public void setTime (Timestamp time)
    {
        this.time = time;
    }
}

The only difference between the two classes is that they are defined in separate JAR files. SampleApiEntity is packaged in the same JAR as the REST resource class. SampleModelEntity is packaged in a separate JAR with other entity classes. The swagger.yaml file that is generated contains both classes, but lacks information provided by the ApiModel and ApiModelProperty annotations for the SampleModelEntity class.

Here is what I am seeing in the generated swagger.yaml file:

SampleApiEntity:
  type: "object"
  required:
  - "level"
  - "time"
  properties:
    level:
      type: "integer"
      format: "int32"
      description: "level"
    description:
      type: "string"
      description: "description"
    time:
      type: "string"
      format: "date-time"
      description: "time"
    sampleApiEntityId:
      type: "string"
      format: "uuid"
      example: "123e4567-e89b-12d3-a456-426655440000"
      description: "id"
      readOnly: true
  description: "This is a sample entity from the Api package."
SampleModelEntity:
  type: "object"
  properties:
    level:
      type: "integer"
      format: "int32"
    description:
      type: "string"
    time:
      type: "string"
      format: "date-time"
    sampleModelEntityId:
      type: "string"
      format: "uuid"

Can someone help me understand why the ApiModel and ApiModelProperty annotations are not generating output in swagger.yaml?

Timeless answered 12/12, 2017 at 16:26 Comment(1)
I've been doing some research and I've narrowed down the issue. The problem does not appear to be caused simply by the fact that the SampleModelEntity class is packaged in a separate JAR from the REST resource classes. In the pom.xml file for the REST resource package, the dependency JAR that contains SampleModelEntity is declared with the provided scope. The scope appears to be causing the issue.Timeless
T
6

I found the solution. It turned out to be a class loading issue. I had an ear library that I was using to deploy a war library. Both the war and the ear contained a copy of the swagger-annotations artifact. This resulted in loaded annotation classes being different from what was packaged in the ear.

I solved the problem by modifying my pom.xml file for the war library. I added the swagger-annotations as an explicit dependency, and set its scope as provided:

    <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-annotations</artifactId>
        <version>1.5.10</version>
        <scope>provided</scope>
    </dependency>

You can find more information here: https://github.com/swagger-api/swagger-core/issues/2582

Timeless answered 22/2, 2018 at 20:48 Comment(0)
F
4

A little hint if you have a multi module maven project and use the maven swagger plugin. The same problem can appear in this constelation.

|-Module1 ( Rest paths )
 |--> pom.xml
|-Module2 ( Models )
 |--> pom.xml
|--> pom.xml ( Parent pom )

Add the plugin to the parent pom and start it from here.

This prevents the class loading problem and the annotations will be recognized and processed in the right way by the swagger "scanner".

Floreneflorentia answered 16/7, 2018 at 7:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.