I am following the swagger tutorial to swaggerize my web application.
. I am using package scanning and Swagger's BeanConfig for swagger initialization. Is there a way to disable swagger in specific environment (e.g. production)? There are some discussion talking about disabling swagger with SpringMVC
Here is my web.xml
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.jaxrs.listing,
com.expedia.ord.ops.rest
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Hooking up Swagger-Core in your application -->
<servlet>
<servlet-name>SwaggerServlet</servlet-name>
<servlet-class>com.expedia.ord.ops.util.SwaggerServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>SwaggerUI</servlet-name>
<jsp-file>/SwaggerUI/index.html</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>SwaggerUI</servlet-name>
<url-pattern>/api/docs/*</url-pattern>
</servlet-mapping>
Here is my Swagger servlet:
public class SwaggerServlet extends HttpServlet
{
static private final String[] SCHEMES = {"http"};
#Value("${swagger.enable}")
private boolean enableSwagger;
#Value("${swagger.resource.package}")
private String resourcePackage;
#Value("${swagger.host}")
private String host;
#Value("${swagger.basePath}")
private String basePath;
#Value("${swagger.api.version}")
private String version;
#Override
public void init(final ServletConfig config) throws ServletException
{
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
final BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion(version);
beanConfig.setSchemes(SCHEMES);
beanConfig.setHost(host);
beanConfig.setBasePath(basePath);
beanConfig.setResourcePackage(resourcePackage);
beanConfig.setScan(enableSwagger);
}
}
Related
Is there any way to configure Jackson (ConfiguredObjectMapper) which is used for serializing servlet responses?
#Api(name = "rates",
version = "v1",
title = "Rates API")
public class RatesApi {
static Logger LOG = Logger.getLogger(RatesApi.class.getSimpleName());
#ApiMethod(name = "getLatestRates",
path = "latest",
httpMethod = HttpMethod.GET)
public RatesEnvelope getLatestRates(#Named("base") String base) throws BadRequestException,
InternalServerErrorException {
try {
RatesInfo ratesInfo = DatabaseUtils.getLatestRates(base);
return new RatesEnvelope(ratesInfo.getDate(), base, ratesInfo.getTimestamp(), ratesInfo.getRates());
} catch (IllegalArgumentException e) {
throw new BadRequestException(e.getMessage());
} catch (com.googlecode.objectify.NotFoundException e) {
throw new InternalServerErrorException("no available rates");
}
}
}
My problem is RatesEnvelope class contains BigDecimal fields which should be configured with mapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN); to avoid E notation.
web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<servlet>
<servlet-name>CurrencyWebserviceServlet</servlet-name>
<servlet-class>PACKAGE_NAME.backend.servlet.OpenExchangeRatesWebserviceServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>SystemServiceServlet</servlet-name>
<servlet-class>com.google.api.server.spi.SystemServiceServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<param-value>PACKAGE_NAME.backend.spi.RatesApi</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>CurrencyWebserviceServlet</servlet-name>
<url-pattern>/cron/fetchlatest</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>SystemServiceServlet</servlet-name>
<url-pattern>/_ah/spi/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
<!-- Next three lines are for request dispatcher actions -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
</web-app>
Create an instance of Jackson ObjectMapper. Configure as needed by enabling or disabling features you need. Modify your Spring configuration to use it instead of default one. Java configuration would look something like this:
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN);
converter.setObjectMapper(objectMapper);
converters.add(converter);
super.configureMessageConverters(converters);
}
It looks like you're using Cloud Endpoints Frameworks, which doesn't use Jackson annotations. In your case, you'd use an ApiTransformer to achieve what you want. As an example:
#ApiTransformer(RatesEnvelopeTransformer.class)
public class RatesEnvelope {
private BigDecimal someBigDecimalField;
// ...
}
public class RatesEnvelopeTransformer implements Transformer<BigDecimal, String> {
public String transformTo(BigDecimal in) {
return in.toPlainString();
}
public BigDecimal transformFrom(String in) {
return new BigDecimal(in);
}
}
I'm trying to use API documentation using Swagger for my 'org.jboss.resteasy' Rest service. After configuration I can access 'http://localhost:8080/myrestswagger/rest/swagger.json' correctly.
it returns following:
{
"swagger": "2.0",
"info": {
"version": "3.0.0",
"title": ""
},
"host": "localhost:8080",
"basePath": "/myrestswagger/rest",
"schemes": [
"http"
]
}
But I cannot access or generate any data on 'http://localhost:8080/myrestswagger/rest/api-docs', please see my classes.
Rest Service Class :
#Path("/countryDetails")
#Api( value = "/countryDetails", description = "countryDetails" )
public class CountryController {
#Path("/countries")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#ApiOperation(value = "GetCountries", httpMethod = "GET", notes = "Get Countries against Specific URL", response = Country.class)
public List<Country> getCountries() {
List<Country> listOfCountries = new ArrayList<Country>();
listOfCountries = createCountryList();
return listOfCountries;
}
#Path("/country/{id}")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Country getCountryById(#PathParam("id") int id) {
List<Country> listOfCountries = new ArrayList<Country>();
listOfCountries = createCountryList();
for (Country country : listOfCountries) {
if (country.getId() == id) return country;
}
return null;
}
private List<Country> createCountryList() {
Country indiaCountry = new Country(1, "India");
Country chinaCountry = new Country(4, "China");
Country nepalCountry = new Country(3, "Nepal");
Country bhutanCountry = new Country(2, "Bhutan");
List<Country> listOfCountries = new ArrayList<Country>();
listOfCountries.add(indiaCountry);
listOfCountries.add(chinaCountry);
listOfCountries.add(nepalCountry);
listOfCountries.add(bhutanCountry);
return listOfCountries;
}
}
This is the web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>io.undertow.servlet.handlers.DefaultServlet</servlet-class>
<init-param>
<param-name>allowed-extensions</param-name>
<param-value>js, css, png, jpg, gif, html, htm, txt, pdf, jpeg, xml, zip, jar</param-value>
</init-param>
<init-param>
<param-name>disallowed-extensions</param-name>
<param-value>class, war</param-value>
</init-param>
</servlet>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<!--While using Spring integration set resteasy.scan to false or don't configure resteasy.scan parameter at all -->
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>
io.swagger.jaxrs.listing.ApiListingResource,
io.swagger.jaxrs.listing.SwaggerSerializers
</param-value>
</context-param>
<servlet>
<servlet-name>Jersey2Config</servlet-name>
<servlet-class>io.swagger.jaxrs.config.DefaultJaxrsConfig</servlet-class>
<init-param>
<param-name>api.version</param-name>
<param-value>3.0.0</param-value>
</init-param>
<init-param>
<param-name>swagger.api.basepath</param-name>
<param-value>http://localhost:8080/myrestswagger/rest</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
This is my pom.xml dependancy (maven.project)
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>1.5.9</version>
</dependency>
You don't need both swagger.json and api-docs. Both are common names to describe the Swagger definition from your server, which can be used--as a URL--by Swagger UI to render an interactive view of the API.
From looking at the output of your swagger.json, it looks like you're not scanning your resources. Please see about adding your CountryController to the scanning path for the API.
I am trying to create and Rest API with Spring MVC that consumes JSON:
Controller:
#RestController public class CrawlerController {
#RequestMapping(value = "/checkForMarfeelizableSite", method = RequestMethod.POST)
public ResponseR checkForMarfeelizableSites(#RequestBody List<Entry> list) {
// Response
ResponseR responseR = new ResponseR();
responseR.setOperationResult(OperationResult.OK);
for (Entry entry : list) {
System.out.println("Entry: " + entry);
}
return responseR;
} }
Entry.class
public class Entry {
String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}}
web.xml:
<web-app>
<display-name>Marfeel Marfeelizable Checker</display-name>
<!-- Spring Context -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/marfeel-context.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Servlet -->
<servlet>
<servlet-name>marfeel-crawler-api</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Mapping -->
<servlet-mapping>
<servlet-name>marfeel-crawler-api</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<!-- Welcome file List -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
I've added the Jackson lib (jackson-mapper-asl) in my pom.xml, but I'm receiving a HTTP 415 Error
This is a sample of json that I'm sending:
[{"url": "canda.com"},{"url": "toshiba.es"}]
could you check the followings?
Change
public ResponseR checkForMarfeelizableSites(#RequestBody List
list)
to
public ResponseR checkForMarfeelizableSites(#RequestBody
ArrayList list)
(since List is an interface and therefore cannot create an instance).
Entry.class: add #XmlRootElement above the class name,and an empty contractor (required for web exportable classes)
I have made the below pom.xml entry:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>1.5.0</version>
</dependency>
and created a servlet:
public class SwaggerJaxrsConfig extends HttpServlet {
#Override
public void init(ServletConfig servletConfig) {
try {
super.init(servletConfig);
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.2");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:8080");
beanConfig.setBasePath("/api");
beanConfig.setResourcePackage("com.mypackage.resource");
beanConfig.setScan(true);
} catch (ServletException e) {
System.out.println(e.getMessage());
}
}
}
and added this in web.xml: (I could have skipped web.xml by adding it but I am still usign sevlet 2.5 for some reason
#WebServlet(name = "SwaggerJaxrsConfig", loadOnStartup = 1)
<servlet>
<servlet-name>SwaggerJaxrsConfig</servlet-name>
<servlet-class>com.SwaggerJaxrsConfig</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
I can see the below lines in the log: [org.reflections.Reflections] Reflections took 332 ms to scan 2 urls, producing 250 keys and 1186 values
but then I am getting 404 on http://localhost:8080/api
Do you know what am I doing wrong?
It did not work for me either. So I used following in stead of httpservlet and then it started working
<servlet>
<servlet-name>Jersey2Config</servlet-name>
<servlet-class>io.swagger.jersey.config.JerseyJaxrsConfig</servlet-class>
<init-param>
<param-name>api.version</param-name>
<param-value>1.0.0</param-value>
</init-param>
<init-param>
<param-name>swagger.api.basepath</param-name>
<param-value>http://localhost:8080/api</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
Refer to following link for more details on how i implemented
https://github.com/sanketsw/jax_rs_REST_Example
I'm working with Java, Jetty and Jersey 2.18 (latest for now) hosted on a Google App Engine.
Let say I have a service such that
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/{userId}")
public Response getUser(#PathParam("userId") String userId)
{
...
}
When I do:
return Response.ok()
.entity(user)
.build();
I correctly receive an application/json content-type and body.
But when I do:
return Response
.status(404)
.entity(new ResponseModel(100, "user not found"))
.build();
same as for returning any 4XX or 5XX status, I receive a text/html content-type along with this HTML body:
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>404 Not Found</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Not Found</h1>
</body>
</html>
and not the object I put in .entity()
Edit: Here is my web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app
version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.mypackage.services;org.codehaus.jackson.jaxrs</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
org.glassfish.jersey.server.gae.GaeFeature;
org.glassfish.jersey.server.mvc.jsp.JspMvcFeature;
org.glassfish.jersey.media.multipart.MultiPartFeature;
</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.feature.Trace</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattytern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>home.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring Security Filter -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml </param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>GlobalResponseFilter</filter-name>
<filter-class>com.mypackage.GlobalResponseFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>GlobalResponseFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>everything</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- ** -->
<!-- ** General session timeout in minutes -->
<!-- ** -->
<session-config>
<session-timeout>1440</session-timeout>
</session-config>
</web-app>
ResponseModel is just a basic serializable java class :
import java.io.Serializable;
public class ResponseModel implements Serializable
{
private static final long serialVersionUID = 1L;
private int code;
private Serializable data;
public ResponseModel()
{
}
public ResponseModel(int code, Serializable data)
{
System.err.println("Code " + code + " : " + data);
this.code = code;
this.data = data;
}
public int getCode()
{
return code;
}
public void setCode(int code)
{
this.code = code;
}
public Serializable getData()
{
return data;
}
public void setData(Serializable data)
{
this.data = data;
}
}
Can you try again with the following configuration:
<servlet>
<servlet-name>API</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
...
<init-param>
<param-name>jersey.config.server.response.setStatusOverSendError</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
This flag defines if Jersey - when sending a 4xx or 5xx response status - uses ServletResponse.sendError(flag is false) or ServletResponse.setStatus (flag is true).
Calling ServletResponse.sendError usually resets the response entity and headers and returns a (text/html) error page for the status code.
Since you want to return an own custom error entity, you need to set this flag to true.