How to make swagger working with jersey2 and JAX-RS on tomcat 7 - spring

I am trying to use swagger in order to document my Rest APIs. I use following link to setup with jersey2 and JAX-RS on tomcat
https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-2.X-Project-Setup-1.5
But I could not access either /swagger.json or /api-docs. Its responding with 404.
What am I doing wrong? Is there a workable documentation? Please help....

Probably you can try to better boil down, which part of the documentation is not yet working in your case.
For me, I used Jersey 2.5.1, and swagger-jersey2-jaxrs_2.10 v. 1.3.4.
I went with the solution to initialize Swagger by a bootstrap class which I included in my web.xml.
bootstrap class
public class SwaggerBootstrap extends HttpServlet {
#Override public void init(ServletConfig servletConfig) {
try {
ServletContext sc = servletConfig.getServletContext();
//as of servlet api 2.5
String ctxPath = sc.getContextPath();
String apiversion = "your-api-version";
String hostname = "your-hostname";
ConfigFactory.config().setBasePath("http://"+hostname+":8080"+ctxPath);
ConfigFactory.config().setApiPath("http://"+hostname+":8080"+ctxPath);
ConfigFactory.config().setApiVersion(apiversion);
ConfigFactory.config().setSwaggerVersion(com.wordnik.swagger.core.SwaggerSpec.version());
System.out.println("Swagger:");
System.out.println("api hostname:"+hostname);
System.out.println("context path:"+ctxPath);
System.out.println("api-version:"+apiversion);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Failed to configure swagger");
}
}
web.xml
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.wordnik.swagger.jersey.listing</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>JerseyJaxrsConfig</servlet-name>
<servlet-class>com.wordnik.swagger.jersey.config.JerseyJaxrsConfig</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>SwaggerBootstrap</servlet-name>
<servlet-class>my.package.swagger.SwaggerBootstrap</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
Hope that helps.

Related

Migrate Spring Web Application (web.xml) to Spring Boot Executable Jar

Okay I've done a lot of googling and I can't seem to find a clear answer. Let's keep it as simple as possible. I have a web.xml file
<listener>
<listener-class>A</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springcontexts/*.xml</param-value>
</context-param>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:wsspringcontexts/*.xml</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring_mvc_contexts/*.xml</param-value>
</init-param>
</servlet>
I think I know how to migrate this to Spring Boot ...
#SpringBootApplication(exclude = DispatcherServletAutoConfiguration.class)
#ImportResource("classpath*:springcontexts/*.xml")
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
}
Somewhere in a sub-package...
#Configuration
#EnableWebMvc
public class SpringMVCConfiguration
{
#Bean
public ServletRegistrationBean mvc()
{
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.setConfigLocation("classpath*:spring_mvc_contexts/*.xml");
// the dispatcher servlet should automatically add the root context
// as a parent to the dispatcher servlet's applicationContext
DispatcherServlet dispatcherServlet = new DispatcherServlet(applicationContext);
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/spring/*");
servletRegistrationBean.setName("DispatcherServlet");
return servletRegistrationBean;
}
}
...and we do the above again for the other Servlet
My first problem is how to add the listener "A" to Spring Boot and ensure it runs before the root application is refreshed? Some beans that get configured require some static fields to be setup (legacy code), and this setup is done in listener "A". This works fine when deployed as a standard war using the above web.xml
In addition does the above Spring Boot setup look correct?
Why not put your legacy initialisation in a postConstruct method on a bean ?
Failing that you can add a listener that implements
ApplicationListener<ContextRefreshedEvent>
and overrides
public void onApplicationEvent(final ContextRefreshedEvent event)
Does your Spring Boot setup look OK ? Difficult to tell, though I'd let Spring Boot autoconfigure things like the dispatcher servlet for you and get rid of any XML config if at all possible.

Spring 2.5.5 and jersey with autowired

I am trying to integrate jersey to an existing Spring application (Spring 2.5.5).
Jersey is working fine, but however when I AutoWire an existing spring bean, the object is null.
Below is my web.xml
<servlet>
<servlet-name>fs3web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.fl.fs3.api;org.codehaus.jackson.jaxrs</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>fs3web</servlet-name>
<url-pattern>/fs3/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
And, here my application context xml (obviously this is not complete, since this is a huge application, there is much more bean definitions):
TestPojo is my bean I would like to autowire to my jersey resource.
<context:annotation-config />
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.fl.fs3.api,com.fl.fs3.integration.*.web"/>
Both my jersey resource class and POJO class is in package com.fl.fs3.api
#Component
#Path("/v1/site")
public class SitesApiControllerV1 {
#Autowired TestPojo testPojo;
#GET
#Path("/{folderName}")
#Produces(MediaType.APPLICATION_JSON)
public Response getSite(#PathParam("folderName") String folderName) {
System.out.println("pojo obj:" + testPojo);
return Response.ok("info for " + folderName).build();
}
}
#Component
public class TestPojo {
}
When I start my tomcat, I do not see the expected line in logs:
INFO: Registering Spring bean, hello, of type ..... as a root resource class
When I invoke my service /v1/site/xyz, testPojo object is null.
However, before integrating this to my existing project, I did a sample jersey+spring application, and it worked perfectly. I was able to see 'Registering Spring bean' line in logs.
Any help is appreciated.
Try this, it may be more simplified:
Load spring through web.xml like shown below as normal spring confifuration:
<servlet>
<servlet-name>project-spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:project-spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>project-spring</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
Now load your jersey Resources through Application as shown below:
#ApplicationPath("/rest")
public class ResourceLoader extends Application
{
/* (non-Javadoc)
* #see javax.ws.rs.core.Application#getClasses()
*/
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> classes = new HashSet<Class<?>>();
loadResourceClasses(classes);
return classes;
}
private void loadResourceClasses(Set<Class<?>> classes)
{
classes.add(StudentResource.class);
}
}
Then in your resource:
#Path("student")
class StudentResource
{
private StudentService studentService;
StudentResource(#Context ServletContext servletContext)
{
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
this.transactionService = applicationContext.getBean(StudentService .class);
}
}
There you go.
Spring has been configured with all dependency injections with Jersey!

Spring 3, AbstractAnnotationConfigDispatcherServletInitializer, multiple servlets

With Servlet 2.5 it was possible to use multiple servlets configured in the web.xml file by simple duplicating and editing the following xml tags.
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Is it somehow possible to create multiple servlets using Spring's AbstractAnnotationConfigDispatcherServletInitializer with Servlet 3?
I thought that returning 2 classes in getServletConfigClasses() method and 2 paths in getServletMappings() method would be enough, but that doesn't work as I expected it to.
So, is there a (simple) way to configure multiple servlets using Spring 3 and Servlet 3?
Thank you for your answers!
You can do something like:
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(appContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
ServletRegistration.Dynamic anotherServlet =
container.addServlet("anotherServlet", "com.xxx.AnotherServlet");
anotherServlet.setLoadOnStartup(2);
anotherServlet.addMapping("/another/*");
ServletRegistration.Dynamic yetAnotherServlet =
container.addServlet("yetAnotherServlet", "com.xxx.YetAnotherServlet");
yetAnotherServlet.setLoadOnStartup(3);
yetAnotherServlet.addMapping("/yetanother/*");
}
}
Ofcourse, You could use any of the addServlet() methods as per your convenience.

How do I get a JAX-RS application running on WebSphere 8.5

So I am tring to get a JAX-RS application working on my WebSphere 8.5 instance. I created the following interface...
#Path("service")
public class RestService {
#GET
#Produces("text/plain")
public int getCount(){
return 1;
}
}
And This is my Application...
public class RESTConfig extends Application{
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new Hashset<?>();
classes.add(RestService.class);
return classes;
}
}
And then this is my web.xml...
<servlet>
<servlet-name>Rest Servlet</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>jaxrs.ws.rs.Application</param-name>
<param-value>com.company.rest.RESTConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
....
<servlet-mapping>
<servlet-name>Rest Servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Then I have an EAR configured with the WAR as a module. But when I start everything and try going to http://localhost:[port]/war/rest/app/service I see..
[TIME] 00000115 RequestProces I org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (404 - Not Found) with message 'null' while processing GET request sent to http://localhost:[port]/war/rest/service
Please Help!
WAS8.5 supports v2.4 and v3 servlets. The reason removing your web.xml contents (and using 3.0 code) worked for you is because you had a mistake in the param-name tag of your web.xml. v2.4 servlet works fine in WAS8.5 when you use the correct param-name.
This is incorrect.
<param-name>jaxrs.ws.rs.Application</param-name>
This is correct:
<param-name>javax.ws.rs.Application</param-name>
Details:
http://pic.dhe.ibm.com/infocenter/wasinfo/v8r5/topic/com.ibm.websphere.nd.multiplatform.doc/ae/twbs_jaxrs_configwebxml.html
The RestConfig class (that is defined as the JAX-RS Application) should override getClasses to return the resources:
#Path("app")
public class RESTConfig extends Application{
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new Hashset<?>();
classes.add(RestService.class);
return classes;
}
}
The issue appears to be related to 8.5 only supporting v3 servlets. this seems to fix the issue....
#Path("service")
public class RestService {
#GET
#Produces("text/plain")
public String getCount(){
//Text-Plain cannot be int apparently
return String.valueOf(1);
}
}
#ApplicationPath("rest")
public class RESTConfig extends Application{
//Override no longer needed.
}
This should now deploy fine...
Here was my source IBM
Also, You can try buy changing the below web.xml File
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Also, In Project Facets - Change Web Module version to 3.0
For More Reference Visit: How to deploy a JAX-RS application?

Configuring Grizzly with a web.xml

I can start grizzly and deploy Jersey webservices on it with the following lines.
protected HttpServer create() throws Throwable {
ResourceConfig rc = new PackagesResourceConfig("com.resource", "com.provider");
HttpServer server = GrizzlyServerFactory.createHttpServer(uri, rc);
return server;
}
But is there a way to load a web.xml instead of a ResourceConfig?
<web-app>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.resource, com.provider</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
It seems that there is currently no direct way to configure grizzly with a web.xml. However I have used a partial solution that may be a beginning.
web.xml
First to understand the solution, we must understand what is the meaning of using a web.xml. It is basically use for configure your web application (see this answer for a more detail). In this case we are configuring init-params for the servlet.
The (partial) solution
Instead of using the web.xml and instead of using ResouceConfig.class, we can use Grizzly as our servlet and initializing the parameters.
For example
<web-app>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.resource, com.provider</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
would give something like :
protected HttpServer create() throws Throwable {
HashMap<String, String> initParams = new HashMap<>();
//ServerProperties.PROVIDER_PACKAGES is equal to "jersey.config.server.provider.packages"
initParams.put(ServerProperties.PROVIDER_PACKAGES, "com.resource,com.provider");
//Make sure to end the URI with a forward slash
HttpServer server = GrizzlyWebContainerFactory.create("http://localhost:8080/", initParams);
return server;
}
With this, we can therefore put all the init-params that we want to.
However this solution cannot replace a whole web.xml.

Resources