Prevent Jersey from returning XML for HTTP OPTIONS - jersey

I have a JAX-RS service defined like the below, using Jersey, and is deployed on WebLogic 12.2.1. It works fine.
#Path("/Profile")
public class ProfileServices {
#POST
#Consumes(APPLICATION_JSON)
#Produces(APPLICATION_JSON)
#Path("{ServiceName}")
public Response service(#PathParam("ServiceName") String serviceName, String message) {
...
}
}
However, when calling the service with HTTP OPTIONS, Jersey returned a WADL along with response header Allow: POST,OPTIONS.
<ns0:application xmlns:ns0="http://wadl.dev.java.net/2009/02">
<ns0:doc ns1:generatedBy="Jersey: 2.22.4 2016-11-30 13:33:53" xmlns:ns1="http://jersey.java.net/"/>
<ns0:grammars/>
<ns0:resources base="https://xxx.xxx.xxx.xxx:nnnn/">
<ns0:resource path="XXXXX">
<ns0:method id="service" name="POST">
<ns0:request>
<ns0:representation mediaType="application/json"/>
</ns0:request>
<ns0:response>
<ns0:representation mediaType="application/json"/>
</ns0:response>
</ns0:method>
</ns0:resource>
</ns0:resources>
</ns0:application>
How do I prevent Jersey from returning this WADL? I don't want to disclose the Jersey version to the user. I'm ok with the response status and headers, but I don't want to return the content. If it is not possible, can the Jersey information not be returned?
I am using javax.ws.rs.core.Application and do not require web.xml to specify the servlet.
EDIT
I had in fact override the following method in Application:
#Override
public Map<String, Object> getProperties() {
Map<String, Object> props = new HashMap<>();
props.put("jersey.config.server.wadl.disableWadl", true);
return props;
}
But when I re-deployed, I got the following exception:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=WadlApplicationContext,parent=JaxRsMonitoringListener,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1838803099)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:75)
at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:1012)
at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:1008)
at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:986)
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:617)
at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:184)
at org.glassfish.jersey.server.ApplicationHandler$3.call(ApplicationHandler.java:350)
at org.glassfish.jersey.server.ApplicationHandler$3.call(ApplicationHandler.java:347)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:255)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:347)
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369)
at javax.servlet.GenericServlet.init(GenericServlet.java:244)
...

What worked for me was disabling it in /src/main/webapp/WEB-INF/web.xml like this:
<servlet>
<servlet-name>REST</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.jackson.JacksonFeature;
org.glassfish.jersey.media.multipart.MultiPartFeature;
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.your.packagedir</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.wadl.disableWadl</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Related

Using DispatcherServlet for RestController

I'm currently trying to understand how the Dispatcher Servlet works with the Rest Controller ,but Postman returns 404 on everything I tried thus far.
The rest controller
#RestController
#RequestMapping(value = "/applications")
public class ApplicationController {
private static final Logger logger = LoggerFactory.getLogger(ApplicationController.class);
#Autowired
#Qualifier("ApplDAO")
private ApplDAO applDAO;
#Autowired
ApplicationService objServices;
#RequestMapping(value = "for_user\\{username:\\d+}", method = RequestMethod.GET)
public Application getApp(#PathVariable("username") String username){
Application app = applDAO.getByUsername(username);
return app;
}
}
My web.xml
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring4-servlet.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>springDispatcher</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>springDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I tried using url-pattern /* but with no results.
This is the url I was trying to access http://localhost:8080/project/applications/for_user/username:acid
Is there something wrong with the URL I'm using or have I used the dispatcher wrong.
Here is the spring error
No mapping found for HTTP request with URI [/project/applications/for_user/username:acid
Answered by JB Nizet
Why do you use backslashes instead of slashes in your RequestMapping?
Why do you use the regex \d+ if you want to send username:acid (or
acid?) as user name. Just use value = "/for_user/{username}", and use
http://localhost:8080/project/applications/for_user/acid.

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

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.

How can I let spring+cometd support webscoket?

I use chrome, it always return:
WebSocket connection to 'ws://192.168.1.228:9090/achat/cometd' failed: Unexpected response code: 400
After this error, it use long-polling transport, and success to connect to the server.
How can I let WebSocket work? Is it caused by using SpringFramework 3.1? Thanks.
Web.xml
<!-- Filter to support cross domain requests -->
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
<!--async-supported>true</async-supported-->
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/cometd/*</url-pattern>
</filter-mapping>
<!-- Cometd Servlet -->
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class>
<!--async-supported>true</async-supported-->
<init-param>
<param-name>timeout</param-name>
<param-value>20000</param-value>
</init-param>
<init-param>
<param-name>interval</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>maxInterval</param-name>
<param-value>10000</param-value>
</init-param>
<init-param>
<param-name>maxLazyTimeout</param-name>
<param-value>5000</param-value>
</init-param>
<init-param>
<param-name>long-polling.multiSessionInterval</param-name>
<param-value>2000</param-value>
</init-param>
<init-param>
<param-name>logLevel</param-name>
<param-value>100</param-value>
</init-param>
<init-param>
<param-name>transports</param-name>
<param-value>org.cometd.websocket.server.WebSocketTransport</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cometd</servlet-name>
<url-pattern>/cometd/*</url-pattern>
</servlet-mapping>
Servlet
#Named
#Singleton
#Service
public class ChatService {
#Inject
private BayeuxServer bayeux;
#Session
private ServerSession serverSession;
#Listener("/chat")
public void processHello(ServerSession remote, ServerMessage.Mutable message)
{
Map<String, Object> input = message.getDataAsMap();
String room = input.get("room").toString();
String content = input.get("content").toString();
Map<String, Object> output = input;
bayeux.getChannel("/room/" + room).publish(remote, output, null);
}
}
Follow the CometD Reference Manual, specifically the section that explains how to integrate CometD with Spring.
There you can find an example that uses Spring's XML configuration to setup WebSocket, and an example of how to configure Spring via annotations.
Your question lacks the Spring configuration file and part of the web.xml file so it is difficult to help you in a more detailed way.
Just remember that if you configure CometD in Spring, then you must remove all the CometD configuration from web.xml. You must have only one place where you configure things: either web.xml or Spring's XML/annotations.

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!

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