简体   繁体   中英

CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES not reflected in swagger.json

I am using Jersey, Jax-rs and swagger (+ Spring for injection). My objects have some members and embedded objects with names that are composed of more than one word, and in code I use camelCase. I defined a resolver so they are emitted as underscore as per standard convention. The problem is that swagger apparently doesn't pick up this resolver, so that the objects still appear as camelCase in the swagger json.

Below are some details of my specific configuration:

Snippets of my pom.xml:

<properties>
        <springframework.version>4.2.3.RELEASE</springframework.version>
        <glassfish.jersey.version>2.22.1</glassfish.jersey.version>
    </properties>
<dependencies>

......

<!-- Jersey -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>${glassfish.jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${glassfish.jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${glassfish.jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>${glassfish.jersey.version}</version>
        </dependency>

<!-- swagger documentation -->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-jersey2-jaxrs</artifactId>
            <version>1.5.0</version>
        </dependency>

.....

</dependencies>

I am using annotations only, so my web.xml is empty and I have an AppInitializer class. The Swagger servlet is initialized in the class

public class AppInitializer implements WebApplicationInitializer {

    public void onStartup(ServletContext container) throws ServletException {

        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(MongoDbConfig.class);
        ctx.register(CORSResponseFilter.class);
        ctx.setServletContext(container);

        container.addListener(new ContextLoaderListener(ctx));
        container.addListener(new RequestContextListener());

        ServletRegistration.Dynamic servlet = container.addServlet("jersey-servlet",
                new org.glassfish.jersey.servlet.ServletContainer());
        servlet.setInitParameter("jersey.config.server.provider.packages", "io.swagger.jaxrs.listing,com.my.server.config,com.my.server.resource");
        servlet.setLoadOnStartup(1);
        servlet.addMapping("/api/*");

        ServletRegistration.Dynamic swagger = container.addServlet("SwaggerServlet",
                new io.swagger.jersey.config.JerseyJaxrsConfig());
        swagger.setInitParameter("api.version", "1.0.0");
        swagger.setInitParameter("swagger.api.basepath", container.getContextPath()+"/api");
        swagger.setLoadOnStartup(2);
    }

}

Here is my main model:

import java.io.Serializable;

import javax.validation.constraints.NotNull;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

import io.swagger.annotations.ApiModel;


/**
 * @author Tamar Rosen
 *
 */


@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModel
public class Property implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;    

    private String id;

    @NotNull
    private String name;

    @NotNull
    private String description;

    private PropertyDetails propertyDetails;

    private int monthlyTax;

    private String schemaUrl;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getDescription() {
        return description;
    }

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

    public PropertyDetails getPropertyDetails() {
        return propertyDetails;
    }

    public void setPropertyDetails(PropertyDetails propertyDetails) {
        this.propertyDetails = propertyDetails;
    }

    public int getMonthlyTax() {
        return monthlyTax;
    }

    public void setMonthlyTax(int monthlyTax) {
        this.monthlyTax = monthlyTax;
    }

    public String getSchemaUrl() {
        return schemaUrl;
    }

    public void setSchemaUrl(String schemaUrl) {
        this.schemaUrl = schemaUrl;
    }

}

The CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES in set in a ContextResolver class. This works fine except that its not reflected in the doc generated by swagger.

Below is the ContextResolver implementation:

    import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    private final ObjectMapper mapper;

    public ObjectMapperContextResolver() {
        mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(
            PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
        );
    }

    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }
}

I suspect the problem is that the swagger servlet doesn't see the Context resolver, but I don't know how to fix this problem

OK thank you. You are correct, the swagger introspector cannot follow the mapping by Jackson in this case. You can add the @ApiModelProperty(name = "property_details") annotation on each field to change the interpreted name by the swagger introspector.

Swagger doesnt use the Object Mapper you configure for the service. You need to configure the swagger object mapper with something like:

...
ApplicationConfig.initializeSwaggerConfiguration(); // call from app config
...

/* Swagger configuratoin */
    @PostConstruct
    public static void initializeSwaggerConfiguration() {
        BeanConfig beanConfig = new BeanConfig();
        beanConfig.setSchemes(new String[] { "http" });

        String host = PropertyHandler.getInstance().getValue(PARAM_API_HOST) + ":"
                + PropertyHandler.getInstance().getValue(PARAM_PORT);
        beanConfig.setHost(host);
        beanConfig.setBasePath(PropertyHandler.getInstance().getValue(PARAM_API_BASEPATH));
        beanConfig.setVersion(PropertyHandler.getInstance().getValue(PARAM_VERSION) + " Profile: " + App.getProfile());
        beanConfig.setTitle("SOD Services");
        beanConfig.setDescription("Services for handlign the be");
        beanConfig.setResourcePackage(SERVICES_PACKAGE);
        beanConfig.setScan(true);
        Json.mapper().setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
    }

When you configure the swagger, my understanding is that Swagger by default use this singleton to be used on swagger api.

Just notice that your Swagger-ui make break because the "basePath" property change as well to "lower_case_with_underscores" as notice here: https://github.com/swagger-api/swagger-core/issues/947

I hope this helps someone Regards

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM