SOAP web service implementation method with #Autowired service gave null pointer exception - java

I am new for spring mvc with soap web service.
I have made one web project using spring-mvc, which has #Controller that can handle website view (using model). For business logic, have used #Service and #Repository class.
Now, I am making web service which has same business logic that is working for website view. For that I made one web service class and #Autowired existing #Service for business logic. But that #Autowired class referencing null.
Below is my sample project code, In which
I have made service implementation class and autowired service class for business logic and tomcat catalina com.sun.xml.ws.server.sei.TieHandler.createResponse null
java.lang.NullPointerException
at com.springmvcmaven.ws.producer.hello.HelloWSImpl.hello(HelloWSImpl.java:34)
dispatcher-servlet.xml
<context:annotation-config/>
<context:component-scan base-package="com.springmvcmaven" />
<mvc:annotation-driven/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp" />
pom.xml
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.10</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<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>hello</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
sun-jaxws.xml
<?xml version="1.0" encoding="UTF-8"?>
<endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime">
<endpoint implementation="com.springmvcmaven.ws.producer.hello.HelloWSImpl" name="hello" url-pattern="/hello"/>
</endpoints>
Model Class - User.java
public class User
{
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
Model Controller for web - HomeController.java
#Controller
public class HomeController
{
/**
* Simply selects the home view to render by returning its name.
* #param locale
* #param model
* #return
*/
#Autowired
#Qualifier(value = "homeService")
#Lazy(true)
private HomeService service;
#RequestMapping(value = "/home.do", method = RequestMethod.GET)
public String home(Locale locale, Model model)
{
System.out.println("Home Page Requested, locale = " + locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate);
return "home";
}
#RequestMapping(value = "/user.do", method = RequestMethod.POST)
public String user(#Validated User user, Model model)
{
System.out.println("User Page Requested");
model.addAttribute("userName", service.wsCall(user));
return "user";
}
}
HomeService.java
public interface HomeService
{
public String wsCall(User user);
}
HomeServiceImpl.java
#Service(value = "homeService")
public class HomeServiceImpl implements HomeService
{
#Override
public String wsCall(User user)
{
return "Bravo " + user.getUserName() + " !!";
}
}
Web service class interface - HelloWS.java
#WebService(name="hello")
#SOAPBinding(style = SOAPBinding.Style.RPC)
public interface HelloWS
{
#WebMethod
public String hello(User user);
}
web service implementation class - HelloWSImpl.java
#WebService(endpointInterface = "com.springmvcmaven.ws.producer.hello.HelloWS")
public class HelloWSImpl implements HelloWS
{
#Autowired
#Qualifier(value = "homeService")
#Lazy(true)
private HomeService service;
/**
* This is a sample web service operation
* #param user
* #return
*/
#Override
public String hello(User user)
{
return service.wsCall(user);
}
}
web service client call
public class HelloClient
{
public static void main(String[] args)
{
try
{
URL wsdlURL = new URL("http://localhost:8080/SpringMVCMaven/hello?wsdl");
//check above URL in browser, you should see WSDL file
//creating QName using targetNamespace and name
QName qname = new QName("http://hello.producer.ws.springmvcmaven.com/", "HelloWSImplService");
Service service = Service.create(wsdlURL, qname);
//We need to pass interface and model beans to client
HelloWS helloWS = service.getPort(HelloWS.class);
User user = new User();
user.setUserName("JIya");
System.out.println(helloWS.hello(user));
}
catch(Exception e)
{
System.out.println("EXCEPTION => \n" + e);
}
}
}
Kindly direct me, what I am missing from these code. Is this proper way ?
Thanks in advance.

Related

HTTP 500 error when trying to produce JSON using REST

Trying to produce JSON code from database entries using rest but I am getting a HTTP 500 error code
#Path("product")
public class ProductResource {
#GET
#Produces({ MediaType.APPLICATION_XML })
public List<Product> getProductInformation() {
return ProductDAO.instance.getProductInformation();
}
}
^^ This is the class I have mapped to the resource I am trying to access
It then accesses the ProductDAO class which gets the info from the database and adds it to a HashMap (This part seems to work fine)
public enum ProductDAO {
instance;
private Map<Integer, Product> productMap = new HashMap<Integer, Product>();
private ProductDAO() {
loadFromDb();
}
public Map<Integer, Product> loadFromDb() {
productMap.clear();
try {
Connection conn = Utils.getConnection();
PreparedStatement psmt = conn.prepareStatement("SELECT * FROM products");
ResultSet rs = psmt.executeQuery();
while (rs.next()) {
Product p = new Product(rs.getInt("id"), rs.getString("description"), rs.getInt("CategoryId"),
rs.getDouble("price"), rs.getInt("QuantitySold"), rs.getString("image"));
productMap.put(productMap.size() + 1, p);
System.out.println(productMap);
}
} catch (Exception e) {
e.printStackTrace();
}
return productMap;
}
public List<Product> getProductInformation() {
List<Product> product = new ArrayList<Product>();
product.addAll(productMap.values());
return product;
}
I have 4 test entries in the database currently.
When I add a system.out.println() for the HashMap I get the following output to the console:
Database connection established
{1=myApp.Product#20c427e5}
{1=myApp.Product#20c427e5, 2=myApp.Product#610e026a}
{1=myApp.Product#20c427e5, 2=myApp.Product#610e026a, 3=myApp.Product#2e0456eb}
{1=myApp.Product#20c427e5, 2=myApp.Product#610e026a, 3=myApp.Product#2e0456eb, 4=myApp.Product#5241c547}`
My pom.xml is as follows:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.framesinmind</groupId>
<artifactId>FramesIM</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>FramesIM</name>
<build>
<finalName>FramesIM</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<jersey.version>2.16</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
Web.xml as follows:
<?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>myApp</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
The Java classes are all part of the 'myApp' package
When trying to access the url 'http://localhost:8080/FramesIM/rest/product' I get the HTTP 500 error. Any ideas?
The internal server error is because you need to code the Product class with the annotations and cannot directly pass the list as response. Please follow the code below.
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAccessType;
#XmlRootElement(name = "product")
#XmlAccessorType (XmlAccessType.FIELD)
public class Product {
String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "products")
#XmlAccessorType (XmlAccessType.FIELD)
public class Products
{
#XmlElement(name="product")
private List<Product> products;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("product")
public class ProductResource {
#GET
#Produces(MediaType.APPLICATION_XML)
public Products getProductInformation() {
List<Product> product = ProductDAO.instance.getProductInformation();
Products products = new Products();
products.setProducts(product);
return products;
}
}
The response below is the sample output
<products>
<product>
<id>12</id>
</product>
</products>

Maven, Jersey, JSON, Tomcat, Error MessageBodyWriter not found for media type=application/json

I get this error when I try to see JSON response in my browser. I read a lot of posts on stack witch are similar but nothing work. Browser return "Error 500". Intellij IDEA return error "Error MessageBodyWriter not found for media type=application/json". Here is my code:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupId</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-entity-filtering</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<properties>
<jersey.version>2.23.2</jersey.version>
</properties>
</project>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<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>app</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>Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
MessageService:
package app.resource;
import app.model.Message;
import app.service.MessageService;
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;
import java.util.List;
#Path("messages")
public class MessageResource {
MessageService messageService = new MessageService();
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Message> getMessages()
{
return messageService.getAllMessages();
}
#GET
#Path("/{messageId}")
#Produces(MediaType.APPLICATION_JSON)
public Message test(#PathParam("messageId") long id)
{
return messageService.getMessage(id);
}
}
Message class:
package app.model;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;
#XmlRootElement
public class Message {
private long id;
private String message;
private Date created;
private String author;
public Message()
{
}
public Message(long id, String message, String author) {
this.id = id;
this.message = message;
this.created = new Date();
this.author = author;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
Old post, but I figured it could help someone. I can across the same issue playing around with Apache Tomcat 9.0.36 and Jersey. This error is due to a missing media dependency. Here are my Jersey POM dependencies that worked for me:
<!-- Jersey dependencies -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.29.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.29.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.29.1</version>
</dependency>
<!-- Jersey media type files, including XML -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
<version>2.29.1</version>
</dependency>
<!-- Jersey JSON entity providers -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.29.1</version>
</dependency>
You can read more about Jersey supported media types in their documentation.

Swagger2feature CXF xml configuration

I am trying to configure CXF nonSpring with Swagger to see the json documentation generated, but I can not see where the url that was generated from Swagger is.
Here is my code:
pom.xml
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-service-description-swagger</artifactId>
<version>3.1.11</version>
</dependency>
web.xml
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXFServlet</display-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value> com.bank.AdminApplication </param-value>
</init-param>
<init-param>
<param-name>jaxrs.application.address.ignore</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>jaxrs.features</param-name>
<param-value>
org.apache.cxf.jaxrs.swagger.Swagger2Feature
(basePath=/swagger/apiā€‹docs)
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
main interface with definitions and annotations:
#Path("/")
#Api(value="/swagger/apidocs")
public interface ApiClient {
#GET
#Path("endpoint/consult")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Consult test Endpoint", response = Response.class)
public Response consultEndpoint() throws ServiceException;
}
I go to: http://localhost:8080/webapp/swagger/apidocs
but nothing appears
Any recommendation?
Well, finally I found how to integrate CXF non spring with swagger; here is the code:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>coop.bancocredicoop.test</groupId>
<artifactId>test-api-cxfnonspring-swagger</artifactId>
<version>1.0.0</version>
<name>test-api-cxfnonspring-swagger</name>
<description>Servicios test api rest</description>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-service-description-swagger</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
web.xml
<?xml version="1.0"?><!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"><web-app><servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.AdminApplication</param-value>
</init-param>
<init-param>
<param-name>jaxrs.address</param-name>
<param-value>/</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping></web-app>
AdminAplication.java
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import org.apache.cxf.jaxrs.swagger.Swagger2Feature;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
public class AdminApplication extends Application {
HashSet<Object> singletons = new HashSet<Object>();
public AdminApplication() {
singletons.add(new PersonService());
}
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
return set;
}
#Override
public Set<Object> getSingletons() {
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
mapper.setAnnotationIntrospectors(primary, secondary);
JacksonJsonProvider jaxbProvider = new JacksonJsonProvider();
jaxbProvider.setMapper(mapper);
singletons.add(jaxbProvider);
Swagger2Feature feature = new Swagger2Feature();
feature.setContact("Pablo Garcia");
feature.setDescription("api Description");
feature.setPrettyPrint(true);
feature.setTitle("api title");
singletons.add(feature);
return singletons;
}
}
PersonService.java
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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;
import javax.ws.rs.core.Response;
#Path("/people")
#Produces(MediaType.APPLICATION_JSON)
#Api(value = "/people")
public class PersonService {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/person/{id}/")
#ApiOperation(
value = "api value",
notes = "api notes "
)
public Response getPerson(#PathParam("id") String personId) throws Exception {
PersonResponse p = new PersonResponse();
return Response.ok(p).build();
}
}
And finally, a simple POJO PersonResponse:
public class PersonResponse {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

Jackson Serializer not invoked Jersey Jax-RS

Developing JAX-RS app and struggle a problem.
Need to customize json-output from my resource so configured Jersey(2.22.2) to use Jackson(2.5) parser instead default Moxy (according to this answer).
Here is pom.xml fragment
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
</dependencies>
<properties>
<jersey.version>2.22.2</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
I also configured web.xml file to use Jackson by default
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
com.mycompany.myresourcepackage
com.fasterxml.jackson.jaxrs
</param-value>
</init-param>
But resource output is deffer from what I configure with annotations and serializer.
Here is model to represent as json
#XmlRootElement(name = "geo")
public class Geometry {
public Geometry() {
coordinates = new ArrayList<List<Double>>();
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#JsonSerialize(using = CoordinatesSerializer.class)
public List<List<Double>> getCoordinates() {
return coordinates;
}
public void setCoordinates( List<List<Double>> coordinates) {
this.coordinates = coordinates;
}
#JsonProperty("tp")
private String type;
private List<List<Double>> coordinates;
}
And serializer
protected CoordinatesSerializer(Class<List<List<Double>>> t) { }
private static final long serialVersionUID = 1L;
#Override
public void serialize(List<List<Double>> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException {
try {
jgen.writeArrayFieldStart("motherfucking-coordinates");
int coordinates_size = value.size();
for (int i = 0; i < coordinates_size; i++) {
jgen.writeStartArray();
jgen.writeNumber(value.get(i).get(0));
jgen.writeNumber(value.get(i).get(1));
jgen.writeEndArray();
}
jgen.writeEndArray();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
And here is resource fragment
#GET
#Path("/route/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Geometry(#PathParam("id") int id) {
// construct and return object
}
Response json is not customized at all.
{"geometry":{"coordinates":["27.56 53.9","27.58 53.88","27.55 53.94"],"type":"LineString"},"id":"1","type":"Feature"}
Desired output is
{"geometry":{"coordinates":[[27.56, 53.9],[27.58, 53.88],[27.55, 53.94]],"type":"LineString"},"id":"1","type":"Feature"}
Thanks a lot.
I finally managed to configure Jersey project to use Jackson JSON parser instead of Moxy(default). The application is running at Glassfish JEE Server.
Maven dependencies
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
Than you need to create class with extends org.glassfish.jersey.server.ResourceConfig. The object of the class is created when app is first loaded.
public class MyApplication extends ResourceConfig {
public MyApplication() {
// create custom ObjectMapper
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// create JsonProvider to provide custom ObjectMapper
JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
provider.setMapper(mapper);
register(provider);
register(JacksonFeature.class);
packages("your.resources.package");
}
}
And created MyApplication class should be registered in web.xml file (to be actually created). Edit section of web.xml.
<servlet>
<servlet-name>App</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>your.app.package.MyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Listed steps are enough to register Jackson JSON Parser as default for Jersey Jax-RS app.

WebSphere Liberty JSR-250 implementation (RolesAllowed)

In order to use the security annotations of JSR-250 (RolesAllowed, PermitAll, DenyAll):
In Jersey, you would register the RolesAllowedDynamicFeature class.
In RESTeasy, you would use the web.xml config:
<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>
Both of these rely on the implementation of SecurityContext.isUserInRole(), but it seems that WebSphere Liberty Profile does not.
How do we get this to work in WebSphere Liberty Profile (WLP)?
I used a minimal example:
Create a resource class/method with #RolesAllowed:
#Path("/rest")
public class HelloWorld {
#GET
#RolesAllowed("ANYTHING")
public Response hello() {
return Response.ok("Hello World").build();
}
}
Set your SecurityContextImpl in a filter, overriding isUserInRole() to always returns true;
Enable "role-based security" for the JAX-RS implementation. (Jersey or RESTeasy, etc as above. For WLP, I had to add the appSecurity-2.0 feature)
And you should have a working example.
However, it appears that WebSphere Liberty Profile returns 403 Forbidden even though isUserInRole returns true.
Does anyone know how to properly use the #RolesAllowed annotation in Liberty and what I might be missing?
Code
#ApplicationPath("/")
public class MyApplication extends Application {
public MyApplication() {}
}
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext ctx) throws IOException {
System.out.println("Setting SecurityContext..");
ctx.setSecurityContext(new MySecurityContext("someuser", "anyrole"));
}
}
public class MySecurityContext implements SecurityContext {
private String user;
private String role;
public static class MyPrincipal implements Principal {
private String name;
public MyPrincipal(String name) { this.name = name; }
#Override public String getName() { return name; }
}
public MySecurityContext(String user, String role) {
this.user = user;
this.role = role;
}
#Override public String getAuthenticationScheme() { return "BASIC"; }
#Override public Principal getUserPrincipal() { return new MyPrincipal(user); }
#Override public boolean isSecure() { return true; }
#Override
public boolean isUserInRole(String role) {
return true;
}
}
#Path("/test")
public class HelloWorld {
#GET
#RolesAllowed("doesntmatter")
public Response hello() {
return Response.ok("Hello World").build();
}
}
pom.xml (dependencies only)
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
server.xml
Code works with the appSecurity feature disabled. Does not work with it enabled.
<server description="test">
<featureManager>
<feature>jaxrs-2.0</feature>
<feature>localConnector-1.0</feature>
<!-- <feature>appSecurity-2.0</feature> -->
</featureManager>
<webApplication id="RoleTest" location="RoleTest.war" name="RoleTest"/>
<httpEndpoint httpPort="9081" httpsPort="9444" id="defaultHttpEndpoint"/>
<!-- below lines are required when appSecurity feature is loaded -->
<!--
<keyStore id="defaultKeyStore" password="{xor}Lz4sLCgwLTtu"/>
<basicRegistry id="basic" realm="BasicRegistry">
<user name="username" password="password" />
</basicRegistry>
-->
</server>
May be you can try this:
1 server.xml
<server description="test">
<featureManager>
<feature>jaxrs-2.0</feature>
<feature>appSecurity-2.0</feature>
</featureManager>
<webApplication id="RoleTest" location="RoleTest.war" name="RoleTest">
<application-bnd>
<security-role name="ANYTHING">
<user name="username" />
</security-role>
<security-role name="AuthenticationRole">
<user name="username" />
</security-role>
<security-role name="AllAuthenticated">
<special-subject type="ALL_AUTHENTICATED_USERS" />
</security-role>
</application-bnd>
</webApplication>
<httpEndpoint httpPort="9081" httpsPort="9444" id="defaultHttpEndpoint" />
<basicRegistry id="basic" realm="BasicRegistry">
<user name="username" password="password" />
</basicRegistry>
</server>
2 Java Code
Create a MyApplication class and a resource class/method with #RolesAllowed:
#ApplicationPath("/")
public class MyApplication extends Application {
public MyApplication() {}
public Set<Class<?>> getClasses(){
Set<Class<?>> classes = new HashSet();
classes.add(HelloWorld.class);
return classes;
}
}
#Path("/rest")
public class HelloWorld {
#GET
#RolesAllowed("ANYTHING")
public Response hello() {
return Response.ok("Hello World").build();
}
}
3 web.xml
<web-app 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 web-app_3_0.xsd"
version="3.0">
<display-name>Test Application</display-name>
<description>blablabla</description>
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>requestProcessorAttribute</param-name>
<param-value>requestProcessorAttribute_webcontainer</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>com.xxx.MyApplication</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SecurityContextApp</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>com.xxx.MyApplication</servlet-name>
<url-pattern>/xxx/*</url-pattern>
</servlet-mapping>
<security-constraint id="SecurityConstraint_2">
<web-resource-collection id="WebResourceCollection_2">
<web-resource-name>com.xxx.MyApplication
</web-resource-name>
<description>Protection area for Rest Servlet</description>
<url-pattern>/xxx/rest</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint id="UserDataConstraint_2">
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
<auth-constraint id="AuthConstraint_2">
<role-name>AuthenticationRole</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>test</realm-name>
</login-config>
<security-role id="SecurityRole_1">
<description>blabla</description>
<role-name>ANYTHING</role-name>
</security-role>
<security-role id="SecurityRole_2">
<role-name>AuthenticationRole</role-name>
</security-role>
</web-app>
Any other issues, leave me a message.

Categories

Resources