Add a Controller class to a Servlet using Jersey Annotation getting 404 - java

In the web.xml is defined this servlet mapping:
<servlet>
<servlet-name>JAX-RS External REST Servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>xxx.rest.external.XxxExternalRestApplication</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.feature.DisableWADL</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS External REST Servlet</servlet-name>
<url-pattern>/external/rest/*</url-pattern>
</servlet-mapping>
I cannot modify the web.xml.
I have created a WebAppplicationInitializer in order to get the registered Servlet on the path /external/rest
Here is the code:
package com.xxx.extended.base.config.sailpoint;
import com.xxx.extended.controllers.IRestControllerMarker;
import com.xxx.extended.controllers.LocalManagedEntitlementsRestController;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.web.WebApplicationInitializer;
import javax.servlet.ServletContext;
/**
* Uses to extend parameter of external rest api to include custom controllers
*/
public class XxxExternalRestWebApplicationInitializer implements WebApplicationInitializer
{
private static final Logger log = LogManager.getLogger(XxxExternalRestWebApplicationInitializer.class);
/**
* Rest api servlet name
*/
private static final String REST_SERVLET_NAME = "JAX-RS External REST Servlet";
#Override
public void onStartup(ServletContext servletContext) {
log.debug("Try to get external servlet by name:[{}]", REST_SERVLET_NAME);
var registration = servletContext.getServletRegistration(REST_SERVLET_NAME);
if (registration == null) {
log.error("Could not find external servlet registration. External api will not work!!!!");
return;
}
registration.setInitParameter(ServerProperties.PROVIDER_PACKAGES, LocalManagedEntitlementsRestController.class.getPackageName());
log.debug("Registered the controllers from this package: [{}]",IRestControllerMarker.class.getPackage().getName());
}
}
After the startup of the application the WebApplicationInitializer is actually recognized, but when I am sending a GET request to the controller I get a 404 Not Found, I pretty sure the URL is fine.
Actually it seems not scanning the package to fetch the controllers to show.
My feeling is that because in the Application defined:
xxx.rest.external.XxxExternalRestApplication
the controllers class are registed sigularly, it is not going scan packages.
Here the simplified code of the controller I'm trying to use:
#Path("custom")
public class LocalManagedEntitlementsRestController extends BaseResource
{
private static final Logger log = LogManager.getLogger(LocalManagedEntitlementsRestController.class);
#GET
#Path("/")
public String sayHello()
{
return "Welcome to the world of REST";
}
}

Related

404 in Jersey/Struts application

I am trying to use Jersey to provide a simple web service for my struts application.
When I call the client action I get the following error
com.sun.jersey.api.client.UniformInterfaceException
Message: GET http://localhost:8080/shumer/rest/employee/get returned a response status of 404
servlet declaration in web.xml
<servlet>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>spring.autowire</param-name>
<param-value>byName</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Server resource
#Path("employee")
public class EmployeeResource {
#Autowired
EmpDao empDao;
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Employee> get(#QueryParam("empCode") String empCode) throws Exception {
EmpCriteria criteria = new EmpCriteria();
criteria.setEmpCode(empCode);
return empDao.searchByCondition(criteria);
}
}
Client action
public class EmployeeClientTestAction extends Action {
#Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Client client = Client.create();
WebResource resource = client.resource("http://localhost:8080/shumer/rest/employee/get");
String employees= resource.accept(MediaType.APPLICATION_JSON)
.get(String.class);
System.out.println(employees);
request.setAttribute("employees", employees);
return mapping.findForward("successful");
}
}
I have tried this with and without the /get and the end of the resource url, and with and without a leading / in the EmployeeResource #Path annotation. My guess is that there is somewhere I have to declare where my resources are lcoated at in order for the Jersey servlet to handle them, but I can't figure it out. A point in the right direction would be much appreciated.
EDIT
I have added the following init-param to the servlet element and it is still not working (this package is where my resource class is)
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>shumer.rest.resource</param-value>
</init-param>
in get method write #Path("/get")

Jersey filter registration via web xml not working

I have a filter which should validate Ids of incoming requests if the resource it is send to is annotated with IdValidation.
I tried to add this filter in the web xml as described in this tutorial. However the filter is not invoked when testing a method with the IdValidation annotation.
#Provider
#IdValidation
public class IdValidationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
this.requestContext = requestContext;
MultivaluedMap<String, String> map = requestContext.getUriInfo().getPathParameters();
if (map.containsKey("someId")) {
// Do some validation and abort if nessecary
}
}
}
The interface I use to add this filter.
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
public #interface IdValidation {}
The web xml. I tried without the provider classnames at first because I think this is not necessary since the filter is in the same package, but this didn't work either.
<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>my.package</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>my.package.IdValidationFilter</param-value>
</init-param>
</servlet>
try this code -
import java.io.IOException;
import java.lang.annotation.Annotation;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
#Provider
public class IdValidationFilter implements ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
#Context
private HttpServletRequest request;
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
for (Annotation annotation : resourceInfo.getResourceMethod().getDeclaredAnnotations()) {
if (IdValidation.class == annotation.annotationType()) {
this.requestContext = requestContext;
MultivaluedMap<String, String> map = requestContext.getUriInfo().getPathParameters();
if (map.containsKey("someId")) {
// Do some validation and abort if nessecary
}
}
}
}
}
If you want to validate a parameter, I suggest you should have a look at Jersey's Bean Validation support.

ExceptionMapper causes "No 'Access-Control-Allow-Origin' header is present on the requested resource" when handling an exception

I have an AngularJS client trying to consume a REST Web Service on Wildfly.
It works when the server returns an object, but when an exception is thrown, I'm getting the following message:
XMLHttpRequest cannot load
http://localhost:8080/ProdutosBackend-0.0.1-SNAPSHOT/rest/user/create.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:51647' is therefore not allowed
access. The response had HTTP status code 500.
I tried lots of combinations of headers and filters, but nothing can make this works.
Client code:
var user = {
email : $scope.signUpData.email,
password : $scope.signUpData.password,
name : $scope.signUpData.name
};
$http.post(
'http://localhost:8080/ProdutosBackend-0.0.1-SNAPSHOT/rest/user/create',
user).
then(function(data) {
console.log("It works!");
},
function(response) {
console.log(response);
});
Web Service
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import br.com.produtos.business.UserBO;
import br.com.produtos.business.exceptions.BusinessException;
import br.com.produtos.entity.User;
import br.com.produtos.transaction.Transaction;
#Path("/user")
public class UserREST {
#POST
#Path("/create")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({ MediaType.APPLICATION_JSON })
public User createAcount(#Context HttpServletRequest httpServletRequest, User user) throws BusinessException {
if (user.getEmail().equals("fff")) {
throw new BusinessException("Bussiness error.");
}
{...}
return user;
}
}
ExceptionMapper
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
public class ThrowableMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable throwable) {
return Response.status(500).entity(throwable.getMessage()).build();
}
}
Application
#ApplicationPath("/rest")
public class ThisApplication extends Application {
public static CorsFilter cors;
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public ThisApplication() {
CorsFilter filter = new CorsFilter();
filter.getAllowedOrigins().add("*");
cors = filter;
singletons.add(filter);
singletons.add(new ThrowableMapper());
singletons.add(new UserREST());
}
public Set<Class<?>> getClasses() {
return empty;
}
public Set<Object> getSingletons() {
return singletons;
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>ProdutosBackend</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>br.com.produtos.rest.ThisApplication</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<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>
</web-app>
I solved the problem returning the message encapsulated into a json string.
public class ThrowableMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable throwable) {
return Response.status(500).entity("{ \"message\": \"" + throwable.getMessage() + "\" }").build();
}
}

GWT + Spring + No bean named 'dispatch' is defined

while trying to use spring dependency injection instead of guice, getting below error
No bean named 'dispatch' is defined
[WARN] /dispatch/
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'dispatch' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1083)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:274)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1079)
at org.springframework.web.context.support.HttpRequestHandlerServlet.init(HttpRequestHandlerServlet.java:57)
at javax.servlet.GenericServlet.init(GenericServlet.java:212)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:433)
at org.mortbay.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:342)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:463)
Could you please help on this.
web.xml content is as below
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatch</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatch</servlet-name>
<url-pattern>/dispatch/*</url-pattern>
</servlet-mapping>
And SeverModule class is
package com.khush.util.server.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.gwtplatform.dispatch.server.actionvalidator.ActionValidator;
import com.gwtplatform.dispatch.server.spring.HandlerModule;
import com.gwtplatform.dispatch.server.spring.actionvalidator.DefaultActionValidator;
import com.gwtplatform.dispatch.server.spring.configuration.DefaultModule;
import com.khush.util.shared.action.RetrieveAccountsAction;
#Configuration
#Import(DefaultModule.class)
public class ServerModule extends HandlerModule {
public ServerModule() {
}
#Bean
public RetrieveAccountsHandler getRetrieveAccountsHandler() {
return new RetrieveAccountsHandler();
}
#Bean
public ActionValidator getDefaultActionValidator() {
return new DefaultActionValidator();
}
protected void configureHandlers() {
bindHandler(RetrieveAccountsAction.class, RetrieveAccountsHandler.class);
}
}
Regards.
Can you paste in here the content of your applicationContext.xml. I think you forgot to add the tag :
<context:component-scan base-package="package to scan..."/>
Without this tag the Spring can't detect Beans outside the XML file.

Integrating Jetty with RESTEasy

Any links on how to integrate Jetty and RESTEasy? I am kinda stuck trying to configure RESTEasy with Jetty together....and there seems to be no credible help on the web.
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
WebAppContext context = new WebAppContext();
context.setDescriptor("../WEB-INF/web.xml");
context.setResourceBase("../src/webapp");
context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
server.join();
}
My Web.xml is copied directly from:
http://docs.jboss.org/resteasy/docs/1.0.0.GA/userguide/html/Installation_Configuration.html
The error I get back is a HTTP 404 when I try to open up a link in my resource file. Everything looks reasonable on the surface, any suggestions?
My resource file looks like:
package webapp;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
#Path("/*")
public class Resource {
#GET
public String hello() {
return "hello";
}
#GET
#Path("/books")
public String getBooks() {
return "books";
}
#GET
#Path("/book/{isbn}")
public String getBook(#PathParam("isbn") String id) {
return "11123";
}
}
This is the prints that I see when Jetty starts up:
2012-04-10 09:54:27.163:INFO:oejs.Server:jetty-8.1.1.v20120215 2012-04-10 09:54:27.288:INFO:oejw.StandardDescriptorProcessor:NO JSP Support for /, did not find org.apache.jasper.servlet.JspServlet 2012-04-10 09:54:27.319:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/C:/Users/xyz/Anotherproj1/src/webapp} 2012-04-10 09:54:27.319:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/C:/Users/xyz/Anotherproj1/src/webapp} 2012-04-10 09:54:27.381:INFO:oejs.AbstractConnector:Started SelectChannelConnector#0.0.0.0:8080
The follwing works for me:
web.xml:
<web-app xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.resources</param-name>
<param-value>webapp.Resource</param-value>
</context-param>
<context-param>
<param-name>javax.ws.rs.core.Application</param-name>
<param-value>webapp.MyApplicationConfig</param-value>
</context-param>
<!-- set this if you map the Resteasy servlet to something other than /*
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/resteasy</param-value>
</context-param>
-->
<!-- if you are using Spring, Seam or EJB as your component model, remove the ResourceMethodSecurityInterceptor -->
<context-param>
<param-name>resteasy.resource.method-interceptors</param-name>
<param-value>
org.jboss.resteasy.core.ResourceMethodSecurityInterceptor
</param-value>
</context-param>
<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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
With
public class MyApplicationConfig extends Application {
private static final Set<Class<?>> CLASSES;
static {
HashSet<Class<?>> tmp = new HashSet<Class<?>>();
tmp.add(Resource.class);
CLASSES = Collections.unmodifiableSet(tmp);
}
#Override
public Set<Class<?>> getClasses(){
return CLASSES;
}
}
Resource
package webapp;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
#Path("/")
#Produces("text/plain")
public class Resource {
#GET
public String hello() {
return "hello";
}
#GET
#Path("/books")
public String getBooks() {
return "books";
}
#GET
#Path("/book/{isbn}")
public String getBook(#PathParam("isbn") String id) {
return "11123";
}
}
and Main Class
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap;
public class Main {
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
WebAppContext context = new WebAppContext();
context.setDescriptor("./src/main/webapp/WEB-INF/web.xml");
context.setResourceBase("./src/main/webapp");
context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
server.join();
}
}
Are you sure that #Path("/*") is correct path. Try #Path("/") maybe this * is a problem. As far as I know path expressions does not accept regexps.
EDIT
I was wrong, you can use regexps in #Path, at least RESTEasy supports that.
To get RESTEasy and Jetty to work together without a web.xml ensure you have a dependency on resteasy-servlet-initializer in your pom.xml.
This may help (JBoss RESTEasy documentation): https://docs.jboss.org/resteasy/docs/3.0.4.Final/userguide/html/Installation_Configuration.html#d4e111

Categories

Resources