My web application uses Jersey for serving GET requests. Configuration:
#ApplicationPath("/")
public class ApplicationRESTContext extends PackagesResourceConfig {
public ApplicationRESTContext() {
super("controller.api.", "admin.api");
}
}
Since I'm using Glassfish 3.1 and I want to use only annotations, how is possible to configure Jersey with alternative JSPTemplatePath (com.sun.jersey.config.property.JSPTemplatesBasePath) property pointing to /WEB-INF/jsp (I can't put jsps in Web directory because all Jersey is serving all requests /*)?
try this:
#ApplicationPath("/")
public class ApplicationRESTContext extends PackagesResourceConfig {
public ApplicationRESTContext() {
super(new HashMap<String, Object>() {{
put(PackagesResourceConfig.PROPERTY_PACKAGES, "controller.api;admin.api");
put(ServletContainer.JSP_TEMPLATES_BASE_PATH, "my-jsp-templates-path");
}});
}
}
Related
I am trying to upgrade the Jetty from 8 to 9.3. As the default value of _asyncSupported become false so it will show the following error.
java.lang.IllegalStateException: !asyncSupported: stackDumperFilter
at org.eclipse.jetty.server.Request.startAsync(Request.java:2248) at
org.eclipse.jetty.continuation.Servlet3Continuation.suspend(Servlet3Continuation.java:188)
at
org.eclipse.jetty.servlets.ProxyServlet.service(ProxyServlet.java:659)
The servlet is loaded in the code through Google guice's ServletModule in the following way.
public class ProxyModule extends ServletModule {
#Override
protected void configureServlets() {
serve("/someurl/*").with(ProxyServlet.class);
}
}
#Singleton
public static class ProxyServlet extends SuperHttpProxyServlet {
#Inject
public ProxyServlet(#Named("something.proxy") Transparent proxy) {
super(proxy);
}
}
After Jetty 9 upgrade, it will take the default value of _asyncSupported which become false. So it will give exception for the following reason in the jetty library file (Package : org.eclipse.jetty.server).
public AsyncContext startAsync() throws IllegalStateException
{
if (!_asyncSupported)
throw new IllegalStateException("!asyncSupported");
_async.startAsync();
return _async;
}
So how do I make the ProxyServlet asyncSupported (true) when it is called by Google Guice's ServletModule ?
I have tried with annotation but it won't work.
#WebServlet(urlPatterns={"/someurl/*"}, asyncSupported=true, loadOnStartup = 1)
#Singleton
public static class ProxyServlet extends SuperHttpProxyServlet {
#Inject
public ProxyServlet(#Named("something.proxy") Transparent proxy) {
super(proxy);
}
}
But it got failed with the same error.
java.lang.IllegalStateException: !asyncSupported: stackDumperFilter at org.eclipse.jetty.server.Request.startAsync(Request.java:2248) at
Set your stackDumpFilter to be asyncSupported=true
The rule of thumb is, if anything in your filter chain (all filters + servlet) uses async, then all of those filters and servlet must be set to asyncSupported=true.
How to configure a Ninja web application running on Heroku to force the use of SSL, that is, redirect all requests to HTTPS?
Here is the class to add in the conf package:
public class Filters implements ApplicationFilters {
#Override
public void addFilters (List<Class<? extends Filter>> list) {
list.add (HttpsFilter.class);
}
public static class HttpsFilter implements Filter {
#Override
public Result filter (FilterChain filterChain, Context context) {
if ("http".equals (context.getHeader ("X-Forwarded-Proto"))) {
return Results.redirect ("https://" + context.getHostname ()
+ context.getRequestPath ());
}
return filterChain.next (context);
}
}
}
If you look good in the ninja framework documentation it is indicated how to configure it to get what you want
http://www.ninjaframework.org/documentation/configuration_and_modes.html
I know we can map a servlet at runtime since servlet api 3.0, that can be achieved as below:
#Override
public void contextInitialized( ServletContextEvent sce ) {
ServletContext sc = sce.getServletContext();
String servletMapping = "/yourURL";
ServletRegistration sr = sc.addServlet( servletMapping, "org.yourdomain.yourclass" );
sr.setInitParameter( "key", "value" );
sr.addMapping( servletMapping );
}
Is there a similar way of doing this with websockets (using javax.websockets.api)?
The Websocket equivalent of ServletContainerInitializer is the ServerApplicationConfig. It only doesn't require a services file, the Websocket API will proactively scan the WAR and JARs in WAR for any classes implementing ServerApplicationConfig interface and use them. You can in getEndpointConfigs() use ServerEndpointConfig.Builder to programmatically build a Websocket endpoint and return it.
Here's a kickoff example, given that YourEndpoint.class represents the Websocket endpoint you'd like to programmatically add, and you'd like to ignore any scanned classes.
public class YourServerApplicationConfig implements ServerApplicationConfig {
#Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> scannedClasses) {
Set<ServerEndpointConfig> configs = new HashSet<>();
configs.add(ServerEndpointConfig.Builder.create(YourEndpoint.class, "/yourPath").build());
return configs;
}
#Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scannedClasses) {
return Collections.emptySet();
}
}
I am running Restful web-service as standalone application using Jersey.
Below are my service classes which serve's the requests.
LoginServiceImpl.java
#Component
public class LoginServiceImpl implements LoginService {
#Value("${login.service.defaultmessage}")
private String defaultMessage;
#Autowired
private EmLoginDAO emLoginDAO;
#Override
public String defaultCall() {
return defaultMessage;
}
#Override
public String updatePassword(List<Login> userList) {
System.out.println(emLoginDAO + "\n" + userList);
emLoginDAO.save(userList);
return "Passwords Updated...";
}
#Override
public List<Login> getPasswords() {
System.out.println("OBJECT: " + emLoginDAO);
List<Login> userList = null;
userList = emLoginDAO.findAll();
return userList;
}
}
LoginService.java
#Component
#Path("/user")
public interface LoginService {
#GET
public String defaultCall();
#POST
#Path(value = "/print")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.TEXT_PLAIN)
public String updatePassword(List<Login> userList);
#GET
#Path(value = "/getpassword")
#Produces(MediaType.APPLICATION_XML)
public List<Login> getPasswords();
}
Below is my spring configuration file.
<context:component-scan base-package="com.em.login" />
<context:annotation-config />
After starting the service when I call the respective method get called.
But my defaultMessage and emLoginDAO objects are null. So it is not referring to the properties and spring configuration files.
So can any one please help me to get this correct. Or to find a way to set the properties and spring configuration file paths to Jersey.
Update
Closeable server = null;
try {
DefaultResourceConfig resourceConfig = new DefaultResourceConfig(
LoginServiceImpl.class);
resourceConfig.getContainerResponseFilters().add(
new GZIPContentEncodingFilter());
server = SimpleServerFactory.create(serviceurl,
resourceConfig);
System.in.read();
} catch (IOException e) {
} finally {
if (server != null) {
try {
server.close();
} catch (IOException ex) {
}
}
}
I think this is the culprit:
DefaultResourceConfig resourceConfig = new DefaultResourceConfig(LoginServiceImpl.class);
You are using Spring's IOC to create the objects and do the autowiring, but you are not getting the instance from the Spring container. You need to get the LoginServiceImpl instance from the Spring container, and not have Jersey create it (Jersey does not know how to autowire your #Autowired properties.
You should use the Spring integration with Jersey, seen here.
Edit to respond to your comment, you posted this code:
LoginServiceImpl loginServiceImpl = (LoginServiceImpl) SpringApplicationContext.getBean("loginServiceImpl");
DefaultResourceConfig resourceConfig = new DefaultResourceConfig( loginServiceImpl.getClass());
You are creating a loginServiceImpl via the spring container, and I'll bet if you check your autowired fields will be there.
However, the second line where you use loginServiceImpl.getClass() this is going to create a new LoginServiceImpl, which is not the same one as the loginServiceImpl you got from the context, so you still are going to have the same problem.
You could take a look at Microserver, that will do all the wiring between Jersey and Spring for you (and setup a Grizzly webserver). From the tags I notice you are using Spring boot, with Microserver: micro-boot module you can do (in a class in package com.em.login):
public static void main(String[] args){
new MicrobootApp(()->"test-app").run();
}
And it should wire up Grizzly, Jersey & Spring with Spring-boot enabled for any backend (non-Jax-rs) dependencies.
Alternatively without Spring Boot (plain old Jersey and Spring)
public static void main(String[] args){
new MicroserverApp(()->"test-app").run();
}
To do it manually, you will need to add the Jersey-Spring integration jar to your classpath and make sure both are configured in a way that interoperates (i.e. I think a registering Spring ContextListener is essential). There is an example app here.
Have you configured those two in your spring configuration files?
I mean have you annotated EmLoginDAO also as stereotype Component?
I got this working.
Referred the this part of the Jersey documentation.
Below is the code I have used to make this working.
ResourceConfig resourceConfig = new ResourceConfig(LoginServiceImpl.class);
resourceConfig.register(org.glassfish.jersey.server.filter.UriConnegFilter.class);
resourceConfig.register(org.glassfish.jersey.server.spring.SpringComponentProvider.class);
resourceConfig.property(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
resourceConfig.property("contextConfigLocation", "classpath:/spring-config.xml");
URI serviceUri = UriBuilder.fromUri(serviceHost).port(servicePort).build();
server = SimpleContainerFactory.create(serviceUri, resourceConfig);
Thank you all for helping.
I upgraded to Java EE 7 from Java EE 6 and some of my REST services stopped working. Narrowing it down, it appears this change seems to have come about when Jersey switched from Jackson to MOXy in Java EE 7.
My service looks like:
#Stateless
#Path("access")
public class AccessFacadeREST extends AbstractFacade<Access> {
#PersistenceContext(unitName = "AccessServerPU")
private EntityManager em;
public AccessFacadeREST() {
super(Access.class);
}
#POST
#Consumes({"application/xml", "application/json"})
#Produces({"application/xml", "application/json"})
public ObjectResponse create(#Context HttpServletRequest requestContext,
#Context SecurityContext context,
ObjectRequest<Access> req) {
req.setHostname(requestContext.getRemoteAddr());
return AccessValidation.create(em, req);
}
}
Here req is null and so generates a NullPointerException when it is presented using JSON. It works fine when presented as XML. ObjectRequest is a generic class I use to wrap the request with authentication content standard for several different types of requests.
I tested a similar #GET service to return an ObjectRequest<Access> instance filled with junk data. It again works well when using XML, but returns null (with no exception raised) when I attempt to return JSON.
I found Java EE7 REST server no longer returning List as JSON useful to understand the underlying problem, but didn't see how I could get this to work in my situation. My ApplicationConfig class looks like:
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Object> getSingletons() {
Set<Object> set = new HashSet<>();
log.info("Enabling custom Jackson JSON provider");
set.add(new JacksonJsonProvider());
return set;
}
#Override
public Map<String, Object> getProperties() {
Map<String, Object> map = new HashMap<>();
log.info("Disabling MOXy JSON provider");
map.put("jersey.config.disableMoxyJson.server", true);
return map;
}
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(AccessFacadeREST.class);
}
}
I think I need to configure the ApplicationConfig class to use Jackson, but I don't see how to generalize the solutions I've found to cover my situation. So, two questions really:
Have I properly characterized the underlying problem as being some sort of deficiency with MOXy?
How can I fix this using either MOXy or Jackson (I don't have a preference which, just as long as it works)?
Setup:
Netbeans 8.0.2
Glassfish 4.1
JDK 8 / JRE 8U25 (64 bit)
Edit in response to the question below...
The project pom.xml has the following entry:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.4</version>
</dependency>
You should be able to solve this by disabling MOXy (register the class below in getClasses()) and get rid of your set.add(new JacksonJsonProvider()); singleton. I use this for all my GF4 projects to force Jersey to use Jackson.
/**
* Feature to disable Moxy and Enable Jackson processing
*/
private static class Jackson2Feature implements Feature {
#Override
public boolean configure(FeatureContext context) {
final String disableMoxy = PropertiesHelper.getPropertyNameForRuntime(
CommonProperties.MOXY_JSON_FEATURE_DISABLE,
context.getConfiguration().getRuntimeType());
context.property(disableMoxy, true);
// add the default Jackson exception mappers and allow jaxb annotations
context.register(JsonParseExceptionMapper.class);
context.register(JacksonJaxbJsonProvider.class, MessageBodyReader.class, MessageBodyWriter.class);
return true;
}
}