JSONObject sent via JerseyTest coming blank [duplicate] - java

I'm building a RESTful web service. I've been locked in a situation where I'm not able to proceed. I've a DAO (a POJO) that has a JSONObject as a member variable. When I try to make a POST call from client (Postman or user-defined javascript) and try to debug, the value gathered in the getter of the JSONObject is empty ({}) whereas the other members of the class obtain their appropriate values. I've tried annotating the JSONObject and its getter with #XmlElement, #JsonProperty and so on.. Nothing worked.
The class looks like :
package org.somepackage
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonProperty;
import org.json.JSONObject;
#XmlRootElement
public class someClass {
private String someID;
private String someName;
private JSONObject someJsonObject;
public someClass () {
}
public someClass (String id, String name,
JSONObject jsonObj) {
someID=id;
someName=name;
someJsonObject=jsonObj;
}
public String getSomeID() {
return someID;
}
public void setSomeID(String id) {
this.SomeID= id;
}
public String getSomeName() {
return someName;
}
public void setSomeName(String name) {
this.someName= name;
}
public JSONObject getSomeJsonObject() {
return someJsonObject;
}
public void setSomeJsonObject(JSONObject jsonObj) {
this.someJsonObject= jsonObj;
}
}
I appreciate your help!
Thanks.
EDIT
Example JSON
{
"name": "ABCD",
"ID": "P63784433",
"theJSON":{
"string":"foo",
"number":5,
"array":[1,2,3],
"object":{
"property":"value‌​",
"subobj":{
"arr":["foo","ha"],
"numero":1
}
}
}
}
DEPENDENCY
web.xml dependency on Jackson
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.2</version>
</dependency>
RESOURCES AND PROVIDER REGISTER through web.xml
<!-- Register JAX-RS Application -->
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>my.package.MyApplication</param-value>
</init-param>
<!-- Register resources and providers under my.package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package</param-value>
</init-param>
<!-- Register custom provider -->
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>my.package.mapper.ObjectMapperProvider</param-value>
</init-param>`
MyApplication.java
`#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
// Register resources and providers using package-scanning.
packages("my.package");
register(ObjectMapperProvider.class);
}`

The problem is that Jackson doesn't know how to create the JSONObject (at least not without some help). Jackson mainly handle basic type and POJOs. If you want to be able to handle JSONObject (assuming this is the object from org.json), you can add the jackson-datatype-json-org for the Jackson support.
Below is a complete test. Here are the dependencies I used to test
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20141113</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.16</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.16</version>
<scope>test</scope>
</dependency>
Note: The Jackson version I am using for jackson-datatype-json-org is the same Jackson version used by jersey-media-json-jackson 2.16. If you are using a different version of this jersey jackson, you will need to make sure the version of Jackson it pulls in is the same version of jackson-datatype-json-org you are using. This way we are not mixing Jackson versions.
Here's the test using Jersey Test Framework
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.json.JSONObject;
import org.junit.Test;
import static junit.framework.Assert.*;
/**
*
* #author Paul Samsotha
*/
public class JsonOrgTest extends JerseyTest {
public static class Model {
public String firstName;
public String lastName;
public JSONObject other;
// should br private with correct getters and setters
}
#Path("model")
public static class ModelResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response post(Model model) {
return Response.ok(model).build();
}
}
#Provider
public static class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperProvider() {
mapper = new ObjectMapper();
mapper.registerModule(new JsonOrgModule());
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig(ModelResource.class)
.register(ObjectMapperProvider.class)
.register(JacksonFeature.class);
}
#Override
public void configureClient(ClientConfig config) {
config.register(JacksonFeature.class);
config.register(ObjectMapperProvider.class);
}
#Test
public void should_return_org_json_data() {
final String json
= "{\n"
+ " \"firstName\": \"pee\",\n"
+ " \"lastName\": \"skillet\",\n"
+ " \"other\": {\n"
+ " \"age\": 100,\n"
+ " \"birthday\": \"yesterday\"\n"
+ " }\n"
+ "}";
Response response = target("model").request().post(Entity.json(json));
if (response.getStatus() != 200) {
System.out.println(response.getStatus() + ": " + response.readEntity(String.class));
fail("should return data and 200");
} else {
Model model = response.readEntity(Model.class);
JSONObject other = model.other;
System.out.println(other.toString());
assertEquals("pee", model.firstName);
assertEquals("skillet", model.lastName);
assertEquals(100, other.getInt("age"));
assertEquals("yesterday", other.getString("birthday"));
}
}
}
What you should also do is get rid of all the Jackson dependencies you have in your comment above. You only need one dependency for Jackson JSON support.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.16</version>
</dependency>
Also notice the ObjectMapperProvider in the test. You will need to this to register the JsonOrgModule with the ObjectMapper in order for Jackson to be able to handle JSONObject. This is important. If you don't have the ContextResolver, the above example will fail.

Related

Embedded Jersey 3 with Jetty into existing Application

i am trying to embed a HTTP-Server into an existing java Application. My goal is to create a small rest API as an interface to send commands to the server application it runs in.
I planned using Jakarta and Jersey 3 with Jetty as embeded HTTP-Server. My starting point was the following topic which was for Jersey 2 but i tried my luck: Embed jersey in java application
My problem is that i get 404 Not Found back when i try to call http://localhost/login/status in my browser. The page is blank. When i switch to using Grizzly2 as embedded HTTP-Server and type the url in the browser, the result is the same. The only difference in Grizzly2 i could spot is when i only call http://localhost/ i get an error page additionally to the 404 Not Found response back. As soon as i add /login to the url, i get the 404 Not Found response without an error page. What could be the reason the server does not pick up my resources?
I am using the Eclipse IDE. First i created a clean Maven project, added the following dependencies and created my test code:
org.glassfish.jersey.core -> jersey-server
org.glassfish.jersey.containers -> jersey-container-jetty-http
On my first startup i got some missing class errors, searched for the dependencies they are in and added them to the pom. Following is my current test 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test-ee</groupId>
<artifactId>test-ee-embed</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>3.0.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-bom</artifactId>
<version>3.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
</dependency>
</dependencies>
</project>
// LoginserverRestApi.java
package de.l2d;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
#ApplicationPath("/login")
public class LoginserverRestApi extends ResourceConfig {
#GET #Path("/status")
public String status() {
// TODO Return real server statistics.
return "{\"status\":\"ok\"}";
}
}
// RestApiServer.java
package de.l2d;
import java.net.URI;
import org.eclipse.jetty.server.Server;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import jakarta.ws.rs.core.UriBuilder;
public class RestApiServer {
private Server server;
private RestApiServer() {
URI baseUri = UriBuilder.fromUri("http://localhost/").build();
server = JettyHttpContainerFactory.createServer(baseUri, new LoginserverRestApi(), false);
}
public void start() throws Exception {
server.start();
}
public void stop() throws Exception {
server.stop();
}
private static final class SingletonHolder {
protected static RestApiServer instance = new RestApiServer();
}
public static RestApiServer getInstance() {
return SingletonHolder.instance;
}
}
// Main.java
package de.l2d;
public class Main {
public static void main(String[] args) throws Exception {
RestApiServer.getInstance().start();
Thread.currentThread().join();
RestApiServer.getInstance().stop();
}
}
I found the solution to my problem. However, i do not know why it behaves like this.
I had to use the Path annotation instead of the ApplicationPath annotation on the LoginserverRestApi class and additionally construct a ResourceConfig with LoginserverRestApi.class as parameter and pass that Object to the JettyHttpContainerFactory.createServer static method. Following are the two files which differ from the initial post:
// LoginserverRestApi.java
package de.l2d;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
#Path("/login")
public class LoginserverRestApi extends ResourceConfig {
#GET #Path("/status")
public String status() {
// TODO Return real server statistics.
return "{\"status\":\"ok\"}";
}
}
// RestApiServer.java
package de.l2d;
import java.net.URI;
import org.eclipse.jetty.server.Server;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.core.UriBuilder;
public class RestApiServer {
private Server server;
private RestApiServer() {
URI baseUri = UriBuilder.fromUri("http://localhost/").build();
ResourceConfig config = new ResourceConfig(LoginserverRestApi.class);
server = JettyHttpContainerFactory.createServer(baseUri, config, false);
}
public void start() throws Exception {
server.start();
}
public void stop() throws Exception {
server.stop();
}
private static final class SingletonHolder {
protected static RestApiServer instance = new RestApiServer();
}
public static RestApiServer getInstance() {
return SingletonHolder.instance;
}
}

File upload with Jersey 2 and Jetty

Hello everyone.
I developed a webservice which runs on Jetty with a RESTful API using Jersey 2.
I later had to create a file upload method (mainly for XLS/XML files) and I tried to use Jersey 2's Multipart libraries for it.
However, as the server starts, it throws immediately a strange exception:
2016-09-21 01:13:13.578:INFO:oejs.AbstractConnector:main: Started ServerConnector#17f62e33{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
Exception in thread "main" java.lang.NoClassDefFoundError: org/glassfish/jersey/internal/inject/ExtractorException
at org.glassfish.jersey.media.multipart.internal.FormDataParamValueFactoryProvider.createValueFactory(FormDataParamValueFactoryProvider.java:436)
[.............................................]
Jetty Server
public static void main(String[] args) {
final ResourceConfig resourceConfig = new ResourceConfig(API.class);
resourceConfig.packages("the_package_where_these_classes_are");
resourceConfig.register(MultiPartFeature.class);
ServletHolder jerseyServlet
= new ServletHolder(new ServletContainer(resourceConfig));
Server jettyServer = new Server(8080);
ServletContextHandler context = new ServletContextHandler(jettyServer, "/");
context.addServlet(jerseyServlet, "/*");
try {
jettyServer.start();
jettyServer.join();
} catch (Exception e) {
e.printStackTrace();
} finally {
//jettyServer.destroy();
// got an IllegalStateException uncommenting this and didn't quite understand why
}
}
Endpoints/Jersey/JAX-RS
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
#Path("/")
public class API {
#POST
#Path("test")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetails) throws Exception {
System.out.println(fileDetails.getFileName());
return Response.ok().build();
}
}
Application configs
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import javax.ws.rs.core.Application;
import java.util.Set;
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
resources.add(MultiPartFeature.class);
resources.add(API.class);
return resources;
}
}
Maven dependencies
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.3.11.v20160721</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.23.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.23.2</version>
</dependency>
</dependencies>
Am I using some wrong dependency? Shouldn't this simple service work? I never used Multipart before, so I tried to go by several Internet sources/tutorials.
Thanks in advance!
FIXED
I changed the version to latest in all Jersey dependencies and it worked!
jersey-media-multipart depends on jersey-common , add
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>2.23.2</version>
</dependency>
For me worked like below:
final ResourceConfig resourceConfig = new ResourceConfig(ApplicationConfig.class);
resourceConfig.packages("com.econorma.rest");
resourceConfig.register(MultiPartFeature.class);
ServletHolder jerseyServlet = new ServletHolder(new ServletContainer(resourceConfig));
This is ApplicationConfig class
#ApplicationPath("/")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> resources = new HashSet<Class<?>>();
resources.add(MultiPartFeature.class);
resources.add(EntryPoint.class);
return resources;
}
#Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("jersey.config.server.provider.packages", "com.econorma.rest");
return properties;
}
}
Jersey provides examples for corresponding versions. You can add below dependency to project and by using 'Download sources' feature of IDE you can download source code for this example.By clicking pom parent you can see all examples for same jersey version as well.Hope it helps!
<dependency>
<groupId>org.glassfish.jersey.examples</groupId>
<artifactId>multipart-webapp</artifactId>
<version>${jersey.version}</version>
</dependency>

Unable to create REST response using #Proxy and Jackson

I've encountered a problem with Jackson serialization for my LoginResp object.
It shows me
Infinite recursion (StackOverflowError) (through reference chain: java.util.logging.LogManager["systemContext"]->java.util.logging.SystemLoggerContext["namedLoggers"]->java.util.Hashtable["global"]->java.util.logging.LoggerWeakRef["referent"]->java.util.logging.Logger["manager"]->java.util.logging.LogManager["systemContext"]->java.util.logging.SystemLoggerContext["namedLoggers"]->java.util.Hashtable["global"]->java.util.logging.LoggerWeakRef["referent"]->java.util.logging.Logger["manager"]->java.util.logging.LogManager["systemContext"]->java.util.logging.SystemLoggerContext["namedLoggers"]->java.util.Hashtable["global"]->java.util.logging.LoggerWeakRef["referent"]-.....
I'm trying to replicate the same scenario and using the same code , as mentioned in this link. But getting the above error. Please help, as I simply wants to write the value of my "resp" bean, to my "someJsonString" variable. Thanks in advance.
These are my dependencies
<properties>
<servlet-api-version>3.1.0</servlet-api-version>
<spring-webmvc-version>4.2.4.RELEASE</spring-webmvc-version>
<jackson-version>2.6.4</jackson-version>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-api-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-webmvc-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
My LoginResp class
package my.beans.resp;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
#Component
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class LoginResp {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
My REST controller
package my.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import my.beans.req.LoginReqB;
import my.beans.resp.LoginResp;
#RestController
#RequestMapping(path = "/login")
public class LoginC {
#Autowired
private LoginResp resp;
#RequestMapping(method = RequestMethod.POST)
public String authenticateUserLogin(#RequestBody LoginReqB request) {
resp.setUsername("abc");
ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
SimpleFilterProvider filterP = new SimpleFilterProvider().addFilter("loginResp",
SimpleBeanPropertyFilter.filterOutAllExcept("username"));
mapper.setFilterProvider(filterP);
String someJsonString = "";
try {
someJsonString = mapper.writeValueAsString(resp);
} catch (JsonProcessingException e) {
System.out.println(e.getMessage());
}
return someJsonString;
}
}
I solved it.
Observation: Jackson is not able to convert/process a proxy object at line
someJsonString = mapper.writeValueAsString(resp); in try block.
Solution: As proxy objects are wrapped around the actual object. I'm accessing the actual object behind the proxy using the function mentioned here.
Effect: Now, no need to customize my ObjectMapper, i.e.
ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
SimpleFilterProvider filterP = new SimpleFilterProvider().addFilter("loginResp",
SimpleBeanPropertyFilter.filterOutAllExcept("username"));
mapper.setFilterProvider(filterP);
is no longer required.
First of all, don't use System.out.println method on the server side. Always use some logging utility such as log4j slf4j or any other one you might know. However, this is very unlikely a reason for your problem. Judging by the error, you have some circular reference with your logging configuration.Set a break point in your controller to see if you get there before the error occurs or the error occurs even before you attempt to invoke your method. In any case my guess is that you have logging configuration problem and your problem is the result of that and not of your code, which seems to be OK at first glance except System.out.println usage.

ObjectMapper cannot be resolved to a type

I have troubles getting JSON to work. ObjectMapper cannot be resolved. Library is imported correctly.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.json.JSONException;
import net.sf.json.util.*;
import com.fasterxml.jackson.*;
public class Json {
private static final String jsonFilePath = "C:\\Users\\Juergen\\Desktop\\filesForExamples\\mapExample.json";
public static void objectToJSON(HashMap<String, Mat> map) {
//Map<String, Object> mapObject = new HashMap<String, Object>();
ObjectMapper mapper = new ObjectMapper();
try {
objectMapper.writeValue(new File(jsonFilePath), map);
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you are using **maven** project then add the following in the `POM.xml`
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.1</version>
</dependency>
But if you are using a **simple java** project then you need to add the following jars in your class path:
jackson-core-2.1.X,
jackson-databind-2.1.X
Add import com.fasterxml.jackson.databind.ObjectMapper; to your project.

JSONObject as a member variable in POJO not recognized -Jersey

I'm building a RESTful web service. I've been locked in a situation where I'm not able to proceed. I've a DAO (a POJO) that has a JSONObject as a member variable. When I try to make a POST call from client (Postman or user-defined javascript) and try to debug, the value gathered in the getter of the JSONObject is empty ({}) whereas the other members of the class obtain their appropriate values. I've tried annotating the JSONObject and its getter with #XmlElement, #JsonProperty and so on.. Nothing worked.
The class looks like :
package org.somepackage
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonProperty;
import org.json.JSONObject;
#XmlRootElement
public class someClass {
private String someID;
private String someName;
private JSONObject someJsonObject;
public someClass () {
}
public someClass (String id, String name,
JSONObject jsonObj) {
someID=id;
someName=name;
someJsonObject=jsonObj;
}
public String getSomeID() {
return someID;
}
public void setSomeID(String id) {
this.SomeID= id;
}
public String getSomeName() {
return someName;
}
public void setSomeName(String name) {
this.someName= name;
}
public JSONObject getSomeJsonObject() {
return someJsonObject;
}
public void setSomeJsonObject(JSONObject jsonObj) {
this.someJsonObject= jsonObj;
}
}
I appreciate your help!
Thanks.
EDIT
Example JSON
{
"name": "ABCD",
"ID": "P63784433",
"theJSON":{
"string":"foo",
"number":5,
"array":[1,2,3],
"object":{
"property":"value‌​",
"subobj":{
"arr":["foo","ha"],
"numero":1
}
}
}
}
DEPENDENCY
web.xml dependency on Jackson
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.2</version>
</dependency>
RESOURCES AND PROVIDER REGISTER through web.xml
<!-- Register JAX-RS Application -->
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>my.package.MyApplication</param-value>
</init-param>
<!-- Register resources and providers under my.package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package</param-value>
</init-param>
<!-- Register custom provider -->
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>my.package.mapper.ObjectMapperProvider</param-value>
</init-param>`
MyApplication.java
`#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
// Register resources and providers using package-scanning.
packages("my.package");
register(ObjectMapperProvider.class);
}`
The problem is that Jackson doesn't know how to create the JSONObject (at least not without some help). Jackson mainly handle basic type and POJOs. If you want to be able to handle JSONObject (assuming this is the object from org.json), you can add the jackson-datatype-json-org for the Jackson support.
Below is a complete test. Here are the dependencies I used to test
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20141113</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.16</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.16</version>
<scope>test</scope>
</dependency>
Note: The Jackson version I am using for jackson-datatype-json-org is the same Jackson version used by jersey-media-json-jackson 2.16. If you are using a different version of this jersey jackson, you will need to make sure the version of Jackson it pulls in is the same version of jackson-datatype-json-org you are using. This way we are not mixing Jackson versions.
Here's the test using Jersey Test Framework
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.json.JSONObject;
import org.junit.Test;
import static junit.framework.Assert.*;
/**
*
* #author Paul Samsotha
*/
public class JsonOrgTest extends JerseyTest {
public static class Model {
public String firstName;
public String lastName;
public JSONObject other;
// should br private with correct getters and setters
}
#Path("model")
public static class ModelResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response post(Model model) {
return Response.ok(model).build();
}
}
#Provider
public static class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperProvider() {
mapper = new ObjectMapper();
mapper.registerModule(new JsonOrgModule());
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig(ModelResource.class)
.register(ObjectMapperProvider.class)
.register(JacksonFeature.class);
}
#Override
public void configureClient(ClientConfig config) {
config.register(JacksonFeature.class);
config.register(ObjectMapperProvider.class);
}
#Test
public void should_return_org_json_data() {
final String json
= "{\n"
+ " \"firstName\": \"pee\",\n"
+ " \"lastName\": \"skillet\",\n"
+ " \"other\": {\n"
+ " \"age\": 100,\n"
+ " \"birthday\": \"yesterday\"\n"
+ " }\n"
+ "}";
Response response = target("model").request().post(Entity.json(json));
if (response.getStatus() != 200) {
System.out.println(response.getStatus() + ": " + response.readEntity(String.class));
fail("should return data and 200");
} else {
Model model = response.readEntity(Model.class);
JSONObject other = model.other;
System.out.println(other.toString());
assertEquals("pee", model.firstName);
assertEquals("skillet", model.lastName);
assertEquals(100, other.getInt("age"));
assertEquals("yesterday", other.getString("birthday"));
}
}
}
What you should also do is get rid of all the Jackson dependencies you have in your comment above. You only need one dependency for Jackson JSON support.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.16</version>
</dependency>
Also notice the ObjectMapperProvider in the test. You will need to this to register the JsonOrgModule with the ObjectMapper in order for Jackson to be able to handle JSONObject. This is important. If you don't have the ContextResolver, the above example will fail.

Categories