I want to use jersey framework. I´m running a web Service, using an ant app, on Java EE7. My application server is Glassfish
My method look like this:
package mypackage.service;
...
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
#POST
#Path("createSomething")
#Consumes(MULTIPART_FORM_DATA)
#Produces(APPLICATION_XML)
public Response createSomething(#FormDataParam("upload") InputStream is, #FormDataParam("upload") FormDataContentDisposition formData, #QueryParam("some") String some, #Context HttpServletRequest request) {
String fileLocation = "C:\\UploadFile\\" + formData.getFileName();
//more things, do not matter
try {
ctrl.saveFile(is, fileLocation);
String result = "Successfully File Uploaded on the path " + fileLocation;
return Response.status(Response.Status.OK).entity(result).build();
} catch (IOException e) {
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
I also have an application config:
package mypackage.service;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
#javax.ws.rs.ApplicationPath("")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> resources = new HashSet<>();
addRestResourceClasses(resources);
resources.add(MultiPartFeature.class);
return resources;
}
/**
* Do not modify addRestResourceClasses() method. It is automatically
* populated with all resources defined in the project. If required, comment
* out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(mypackage.service.MYSERVICE.class);
}
}
On myweb.xml I have:
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>mypackage.service.ApplicationConfig</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>mypackage.service</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/createSomething/*</url-pattern>
</servlet-mapping>
I still get the same message:
Caused by: org.apache.catalina.LifecycleException: org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public javax.ws.rs.core.Response
What I´m doing wrong??
It works fine for me. Though I would completely get rid of the Application subclass. It is not needed, and may cause conflict/confusion. Your xml is sufficient configuration, just get rid of the javax.ws.rs.Application <init-param>. I would also look into making the multipart jars only compile-time jars (meaning not built into the war - they might conflict with Glassfish's version). I don't work much with Ant, so I'm not sure how you can do that, but I know it's possible.
Below code worked for me:
Class ->>> add it
Class Property --->> add it
Public Class userREST () {
#POST
#Path("upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response uploadImageFile(#FormDataParam("uploadFile") InputStream fileInputStream,
#FormDataParam("uploadFile") FormDataContentDisposition fileFormDataContentDisposition,
#FormDataParam("FIR_REG_NUM") String FIR_REG_NUM, #FormDataParam("LOGIN_ID") String LOGIN_ID) {
final_json_result = WriteFileInFolder.fileAnalysis(fileInputStream, fileFormDataContentDisposition, FIR_REG_NUM,
LOGIN_ID);
return Response.ok(final_json_result).build();
}// uploadImageFile
package ####.jaxrs.jwt;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import ####.helper.Common###;
import ####.jaxrs.jwt.filters.JWTRequestFilter;
import ####.jaxrs.jwt.filters.JWTResponseFilter;
import ####.service.FileServicesREST;
#ApplicationPath("fileservice")
public class FileJAXRSConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Common###.logging("#ApplicationPath#FileServicesREST...");
Set<Class<?>> clazzes = new HashSet<Class<?>>();
clazzes.add(JWTRequestFilter.class);
clazzes.add(FileServicesREST.class);
clazzes.add(JWTResponseFilter.class);
return clazzes;
}
#Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("jersey.config.server.provider.packages", "####.service");
properties.put("jersey.config.server.provider.classnames", "org.glassfish.jersey.media.multipart.MultiPartFeature");
return properties;
}
}
Don't need to add following in web.xml
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>mha.###.service</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
Related
I have a Tomcat Server and I'm trying to access the index.html file located in the WEB-INF folder, as shown in the picture below
As seen in the picture, when I open http://localhost:9999/index.html it throws a 404
This is my web.xml file:
<?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="CERTHMaTHiSiSOpenAPI" version="3.1">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>OpenAPI</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
api.ws;api.ws.oper
</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>api.ws.oper.Authorization</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>OpenAPI</servlet-name>
<url-pattern>/api/*</url-pattern>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
Is it a problem that it's located under WEB-INF/lib? I tried moving it to WEB-INF with no success.
Edit: This is my Properties > Web Project Settings Tab:
It should be noted that this project has also an API, and under Java Resources > src > ws it has a Conductor.java file with this content:
package ws;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;
import io.swagger.models.Swagger;
import io.swagger.util.Json;
import ws.util.Config;
#ApplicationPath("/")
public class Conductor extends Application {
#Context ServletContext context;
public static Properties properties = new Properties();
public Conductor() {
super();
BeanConfig beanConfig = new BeanConfig();
BeanConfig beanConfig2 = new BeanConfig();
beanConfig.setVersion("3.1.1");
beanConfig.setSchemes(new String[]{"https","http"});
// beanConfig.setHost("localhost:8080");
beanConfig.setBasePath("/api");
beanConfig.setResourcePackage("ws.lg");
beanConfig.setTitle("LG lib Open API");
beanConfig.setScan(true);
Swagger swaglg = new Swagger();
swaglg = beanConfig.getSwagger();
swaglg.setBasePath("/api/lg");
beanConfig2.setVersion("3.1.1");
beanConfig2.setSchemes(new String[]{"https","http"});
// beanConfig.setHost("localhost:8080");
beanConfig2.setBasePath("/api");
beanConfig2.setResourcePackage("ws.sla");
beanConfig2.setTitle("SLA lib Open API");
beanConfig2.setScan(true);
Swagger swaglg2 = new Swagger();
swaglg2 = beanConfig2.getSwagger();
swaglg2.setBasePath("/api/sla");
createSwaggerJsonFile(beanConfig, "swagger-lg.json");
createSwaggerJsonFile(beanConfig2, "swagger-sla.json");
}
// public static final int REST_PORT = 8080;
#Override
public Set<Class<?>> getClasses(){
readProperties();
Set<Class<?>> resources = new HashSet<>();
addRestResourceClasses(resources);
return resources;
}
private void addRestResourceClasses(Set<Class<?>> resources){
resources.add(ws.sla.SLAlibOpenAPI.class);
resources.add(ws.lg.LGlibOpenAPI.class);
resources.add(ws.auth.Authorization.class);
resources.add(ApiListingResource.class);
resources.add(SwaggerSerializers.class);
//to turn off
// resources.add(ws.helpers.MongoModifiersAPI.class);
}
private Properties readProperties() {
String fullPath = context.getRealPath(Config.PROPERTIES_FILE);
InputStream inputStream = null;
try {
inputStream = new FileInputStream(new File(fullPath));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
if (inputStream != null) {
try {
properties.load(inputStream);
} catch (IOException e) {
// TODO Add your custom fail-over code here
e.printStackTrace();
}
}else{
System.err.println("Cannot read config file or no config file exists.");
}
return properties;
}
// /*
private static void createSwaggerJsonFile(BeanConfig beanConfig, String filename) {
try (FileWriter fileWriter = new FileWriter(filename)) {
File f = new File(filename);
fileWriter.write(Json.pretty(beanConfig.getSwagger()));
fileWriter.flush();
System.out.println("File " + filename + " successfully created in " + f.getAbsolutePath());
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
// */
}
You should place your html content inside WebContent folder, not inside web-inf. As it searches the index.html in WebContent and its not there so its showing 404 not found error.
Have a look at this question having similar situation and possible answer
StackOverFlow Question
The solution was to move all the swagger-ui files to a new folder under WebContent (which I called ui), to move the web.xml to WEB-INF and to add a simple servlet-mapping inside web.xml:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/ui/*</url-pattern>
</servlet-mapping>
the problem was that the /api/* url-pattern in the OpenAPI servlet, was consumed by the API.
I had a similar issue. I was confused between html front pages stored in WebContent, and servlets produced by the Java code.
Tomcat searches for .html files in WebContent, as indicated in Context Parameters. The url-parameter of the servlet mapping tells Tomcat where to look for the servlet itself. To me, it's then logical that both locations needs to be different.
My servlet-mapping looks like <url-pattern>/api/*</url-pattern>. My application class contains #Path('/sname'). While keeping WEB-INF/web.xmlas simple as possible, this gives me access to html pages at localhost:8080/ and to servlets at localhost:8080/api/sname.
By default, ROOT war index.html(or welcome-file-list) will be called when you try to access using http://localhost:9999/index.html
If you want to change tomcat default loading page then edit server.xml file and update the following
<Context path="" docBase="new_default_app" />
I need to enable the CORS headers on jersey server side because otherwise the Angualr frontend is getting:
XMLHttpRequest cannot load http://localhost:8080/api/products.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:9000' is therefore not allowed access.
As Jersey documentation explained I set up the filter and made it discoverable using 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>javax.ws.rs.Application</param-name>
<param-value>ny.devtest.endtoend.config.ApplicationConfig</param-value>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-name>ny.devtest.endtoend</param-name>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>*</url-pattern>
</servlet-mapping>
</web-app>
The filter interceptior implementation:
package ny.devtest.endtoend;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
#Provider
public class ResponseCorsFilter implements ContainerResponseFilter {
public ResponseCorsFilter() {
System.out.println("ServerResponseFilter initialization");
}
#Override
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
containerResponseContext.getHeaders().add("X-Powered-By", "Jersey :-)");
containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
containerResponseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
}
}
It is not working.
UPDATE:
package ny.devtest.endtoend.config;
import ny.devtest.endtoend.api.OrderResource;
import org.eclipse.persistence.jaxb.BeanValidationMode;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.moxy.json.MoxyJsonConfig;
import org.glassfish.jersey.moxy.json.MoxyJsonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.validation.ValidationConfig;
import org.glassfish.jersey.server.validation.internal.InjectingConstraintValidatorFactory;
import javax.validation.ParameterNameProvider;
import javax.validation.Validation;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.ContextResolver;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class ApplicationConfig extends ResourceConfig {
private void ApplicationInit(){
// Resources.
packages(OrderResource.class.getPackage().getName());
// Validation.
property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true);
// Providers - JSON.
register(JacksonFeature.class);
register(MoxyJsonFeature.class);
register(new MoxyJsonConfig().setFormattedOutput(true)
.property(MarshallerProperties.BEAN_VALIDATION_MODE, BeanValidationMode.NONE)
.resolver());
}
public ApplicationConfig() {
ApplicationInit();
// Bindings (#Inject)
register(new ApplicationBinder());
}
public ApplicationConfig(AbstractBinder customBinder) {
ApplicationInit();
register(customBinder);
}
#Override // << NOT WORKING
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
containerResponseContext.getHeaders().add("X-Powered-By", "Jersey :-)");
containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
containerResponseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
}
}
Let's try it:
package ny.devtest.endtoend.config;
import org.glassfish.jersey.server.ResourceConfig;
import ...
public class ApplicationConfig extends ResourceConfig {
private void ApplicationInit(){
// Resources.
packages(OrderResource.class.getPackage().getName());
// Register CORS filter.
register(ny.devtest.endtoend.ResponseCorsFilter.class);
// Register the rest you need
...
}
public ApplicationConfig() {
ApplicationInit();
// Bindings (#Inject)
register(new ApplicationBinder());
}
...
}
And configure in web.xml like that
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>ny.devtest.endtoend.config.ApplicationConfig</param-value>
</init-param>
<!-- Add parameter for CORS filter -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
ny.devtest.endtoend
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>*</url-pattern>
</servlet-mapping>
There are a few options to configure this
The way you are trying to do (in the web.xml). With this, you are 1) specifying the wrong init-param name. It should be jersey.config.server.provider.classnames and 2) You need to specify the (fully qualified) name of the filter class as the init-param value, not the package.
You have a java configuration class (ApplicationConfig), so you can just register the filter there
If you are using package (or classpath) scanning it should automatically pick up the filter and register it, because of the #Provider annotation.
For help with 2 or 3, please show your ApplicationConfig class. I'm not sure if you are directly subclassing Application or ResourceConfig. They are different in how they are configured.
Appreciate any help.
I'm facing the problem with the CORS on my newly deployed Tomcat 8.0.30. I keep getting the error below. I am using 127.0.0.1 as the API server address and 192.168.1.100 is the address of my HTTP server.
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '_http://192.168.1.100:8999' is therefore not allowed access. The response had HTTP status code 403.
Read through whole Tomcat documentation, added the cors filter under the tomcat web.xml, as well as the project web.xml, but nothing magic happens here, still getting the same error. Tried both minimal and advanced with init-param, same error.
I am using Spring 4 as my rest api framework. Any more configurations need to be done on the project coding part?
Here are the steps I've done so far:
add cors filter under web.xml, mininal config according to documentation, not working
add cors filter under web.xml, full config, not working as well.
tried to use cors filter from http://software.dzhuvinov.com/cors-filter.html, still not working
Any suggestions?
Add the web.xml configuration
I've tried to change cors.allowed.origins to *, to 127.0.0.1,192.168.1.100, all not working,
remove credentials and maxage
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>http://192.168.1.100</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Suggested by Vishal, changing tomcat version from 8.0 to 8.5, still same issue
XMLHttpRequest cannot load http://127.0.0.1:8080/leyutech-framework-gurunwanfeng/api/ad/getAdInfoByAdType.html?adType=0. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.1.100:8080' is therefore not allowed access. The response had HTTP status code 403.
I've used the custom filter to accomplish this issue, I have no idea why offical tomcat cors filter is not working in my case, Any one can suggest the logic behind this, I am willing to try this out.
Original Post from Tobia
The code is modified from the link above.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void destroy() {
// TODO Auto-generated method stub
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml configuration under current project
<filter>
<filter-name>SimpleCORSFilter</filter-name>
<filter-class>com.example.util.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SimpleCORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I encountered this problem once and I developed a custom handler for a Jetty Web application.
Maybe it can help you.
CORSHandler.hava
import java.io.IOException;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.Request;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
public class CORSHandler extends HandlerWrapper {
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public CORSHandler() {
super();
}
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
// Allow Cross-site HTTP requests (CORS)
response.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
// Accept Content-Type in header
response.addHeader(ACCESS_CONTROL_ALLOW_HEADERS, "content-type");
// Accept GET, POST, PUT and DELETE methods
response.addHeader(ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE");
if (_handler!=null && isStarted())
{
_handler.handle(target,baseRequest, request, response);
}
}
}
Starter.java
import java.io.IOException;
import java.util.logging.Logger;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.SimpleFormatter;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import com.example.config.AppConfig;
import com.example.handlers.CORSHandler;
import com.example.properties.*;
public class Starter {
public static void main( final String[] args ) throws Exception {
Server server = new Server( 8080 );
// Register and map the dispatcher servlet
final ServletHolder servletHolder = new ServletHolder( new CXFServlet() );
HandlerWrapper wrapper = new CORSHandler();
final ServletContextHandler context = new ServletContextHandler();
context.setContextPath( "/" );
context.addServlet( servletHolder, "/rest/*" );
context.addEventListener( new ContextLoaderListener() );
context.setInitParameter( "contextClass", AnnotationConfigWebApplicationContext.class.getName() );
context.setInitParameter( "contextConfigLocation", AppConfig.class.getName() );
wrapper.setHandler(context);
server.setHandler(wrapper);
server.start();
server.join();
}
}
I have some experience using Jersey < 2.0. Now I am trying to build a war application to provide a JSON Webservice API.
I am now struggling for a considerable amount of time trying to configure Moxy and it seams to be way more complicated than what was adding
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
to your web.xml back in Jersey < 2.0.
Is there some possibility to just say "please add json support"?
Currently I just get a lot of Internal Server Error errors without any log entries on the server and just think "I have to do something totally wrong, this can't be so hard"
Can anyone give me a hint?
Please use the below dependency which will do it automatically for you.
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.2.3</version>
</dependency>
If you want to define it in your web.xml file then:
JACKSON:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.jackson.JacksonFeature</param-value>
</init-param>
MOXY
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.moxy.json.MoxyFeature</param-value>
</init-param>
And if using maven add the following dependency to your pom file
JACKSON
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>your jersey version</version>
</dependency>
MOXY
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>your jersey version</version>
</dependency>
You can configure EclipseLink MOXy as the JSON-binding provider by configuring the MOXyJsonProvider class through a JAX-RS Application class.
Example #1
package org.example;
import java.util.*;
import javax.ws.rs.core.Application;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;
public class CustomerApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>(2);
set.add(MOXyJsonProvider.class);
set.add(CustomerService.class);
return set;
}
}
Example #2
package org.example;
import java.util.*;
import javax.ws.rs.core.Application;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;
public class CustomerApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>(1);
set.add(ExampleService.class);
return set;
}
#Override
public Set<Object> getSingletons() {
MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();
moxyJsonProvider.setAttributePrefix("#");
moxyJsonProvider.setFormattedOutput(true);
moxyJsonProvider.setIncludeRoot(true);
moxyJsonProvider.setMarshalEmptyCollections(false);
moxyJsonProvider.setValueWrapper("$");
Map<String, String> namespacePrefixMapper = new HashMap<String, String>(1);
namespacePrefixMapper.put("http://www.example.org/customer", "cust");
moxyJsonProvider.setNamespacePrefixMapper(namespacePrefixMapper);
moxyJsonProvider.setNamespaceSeparator(':');
HashSet<Object> set = new HashSet<Object>(1);
set.add(moxyJsonProvider);
return set;
}
}
For More Information
http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html
http://blog.bdoughan.com/2013/06/moxy-is-new-default-json-binding.html
ACtually, it just worked for me, with the PojoMappingFeature param omitted.
Going to:
http://localhost:8080/webapi/myresource/complexObject/foo
yields this json:
{"name":"foo","value1":1374185178829,"value2":42}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<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>jersey.config.server.provider.packages</param-name>
<param-value>com.example</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
</web-app>
entry point:
package com.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
#Path("myresource")
public class MyResource {
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it!";
}
#Path( "complexObject/{name}" )
#GET
#Produces( { MediaType.APPLICATION_JSON } )
public ComplexObject complexObject( #PathParam( "name" ) String name ) {
return new ComplexObject(name, System.currentTimeMillis(), 42L);
}
}
bean to jsonize:
package com.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
#Path("myresource")
public class MyResource {
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it!";
}
#Path( "complexObject/{name}" )
#GET
#Produces( { MediaType.APPLICATION_JSON } )
public ComplexObject complexObject( #PathParam( "name" ) String name ) {
return new ComplexObject(name, System.currentTimeMillis(), 42L);
}
}
Found this as well working, and was the easiest in resolving the problem (AFAIT)
Include the below dependency in your pom.xml / include the respective JAR file in lib path
<dependency>
<groupId>com.owlike</groupId>
<artifactId>genson</artifactId>
<version>0.99</version>
</dependency
Link here
Just use #XmlElement in place of #XmlAttribute (only attribute receives # prefix, possibly restart your appserver for changed effect!)
I'm developing a 'user settings portlet' where users can effect the search behaviour of multiple other portlets. The way I'd like to do it is by a shared bean. All portlets are in different wars, and I'd rather avoid having all wars in a single ear and using a parent application context, so deployment of portlets can be made autonomously, but haven't had much luck in finding any information on how to do it.
I have followed this blog post to try to deploy an ear file with the wars in them, but after many hours of wrestling I've come no closer to solving my problem...
The directory structure looks like this:
portlets
|--- ear
| \--- src/main/application/META-INF/application.xml
|
|--- jar (contains UserSettings.java)
| \--- src/main/resources/beanRefContext.xml
| \--- src/main/resources/services-context.xml
| \--- src/main/java/com/foo/application/UserSettings.java
|
|--- messagehistory (war, portlet 1)
| \--- [...]
|
|--- settings (war, portlet 2)
| \--- [...]
|
\--- pom.xml
I've tried setting scope="session" like the following:
<bean id="userSettings" class="com.foo.application.UserSettings" scope="session">
<aop:scoped-proxy />
</bean>
But then when I deploy the ear I get java.lang.IllegalStateException: No Scope registered for scope 'session'.
This is the controller för the history portlet, where users can search for message history, with restrictions from the settings portlet. The controller for the settings portlet is identical.
package com.foo;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletSession;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.portlet.bind.annotation.ActionMapping;
import com.foo.application.UserSettings;
import javax.annotation.PostConstruct;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ServletContextAware;
#Controller
#SessionAttributes({"searchQuery", "searchResults"})
#RequestMapping("VIEW")
public class ViewHistory extends ContextLoader implements ServletContextAware {
private UserSettings userSettings;
private ServletContext servletContext;
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
#PostConstruct
public void init() {
ApplicationContext ctx = loadParentContext(servletContext);
servletContext.setAttribute(LOCATOR_FACTORY_KEY_PARAM, "ear.context");
userSettings = (UserSettings) ctx.getBean("userSettings");
}
#ModelAttribute("userSettings")
public UserSettings createUserSettings(Model model) {
model.addAttribute(userSettings);
}
#RequestMapping
public String doSearch(Model model, PortletSession portletSession) {
return "view";
}
#ActionMapping(params = "action=search")
public void searchAction(
Model model,
ActionRequest request, ActionResponse response,
BindingResult bindingResult, SessionStatus status)
{
// do nothing
}
}
The web.xml file for both wars (they are identical) looks like this:
<?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">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>parentContextKey</param-name>
<param-value>ear.context</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<filter>
<filter-name>springFilter</filter-name>
<filter-class>
org.springframework.web.filter.RequestContextFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>springFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Turns out it was really easy just using Spring's #EventMapping annotation for plain JSR 286 eventing. No ear required and no parent application context. I just have my UserSettings.java in a separate jar project and include it as a dependency to both wars.
The controller for the search portlet looks like this:
package com.foo;
import com.foo.event.UserSettings;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.portlet.bind.annotation.ActionMapping;
import javax.portlet.Event;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.portlet.bind.annotation.EventMapping;
#Controller
#RequestMapping("VIEW")
public class ViewHistory {
private UserSettings userSettings = new UserSettings();
#ModelAttribute("userSettings")
public UserSettings createUserSettings(Model model) {
return userSettings;
}
#RequestMapping
public String doSearch(Model model) {
return "view";
}
#ActionMapping(params = "action=search")
public void searchAction(
Model model,
ActionRequest request, ActionResponse response,
#ModelAttribute("userSettings") UserSettings userSettings,
BindingResult bindingResult, SessionStatus status)
{
// do something
}
/**
* Spring calls this whenever an event is received.
* Can be limited to certain event.
*/
#EventMapping
public void handleEvent(EventRequest request) {
Event event = request.getEvent();
if (event.getName().equals("UserSettings")) {
userSettings = (UserSettings)event.getValue();
}
}
}
...and for the settings portlet:
package com.foo;
import com.foo.event.UserSettings;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.portlet.bind.annotation.ActionMapping;
import javax.xml.namespace.QName;
import org.springframework.web.bind.annotation.ModelAttribute;
#Controller
#RequestMapping("VIEW")
public class ViewSettings {
private QName qname = new QName("http:foo.com/usersettings", "UserSettings");
#ModelAttribute
public UserSettings createUserSettings(Model model) {
return new UserSettings();
}
#ActionMapping(params = "action=search")
public void searchAction(
Model model,
ActionRequest request, ActionResponse response,
#ModelAttribute("userSettings") UserSettings userSettings,
BindingResult bindingResult, SessionStatus status)
{
// as soon as an action is triggered (save button is pressed or
// whatever), send the modified UserSettings instance as an
// event to the search portlet (actually any portlet, but I
// only have one that will read events).
response.setEvent(qname, userSettings);
}
#RequestMapping
public String doView(Model model) {
return "view";
}
}