How to create proper JAXB mapping to make Jersey deserialization process happened - json

I have JSON response from WS:
[
{
"name": "Bobby",
"status": "single"
},
{
"name": "John",
"status": "married"
}
]
Here is my wrapper
#XmlRootElement(name = "users")
public class UserListWrapper {
private List<User> users;
#XmlElement(name = "user")
public List<User> getUsers() {
return users;
}
// getters and setters omitted
}
And User class
#XmlRootElement
class User {
private String name;
private String status;
// getters and setters omitted
}
The problem is when Jersey try to deserialize response to my wrapper object. It say
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of com.jersey.test.UserListWrapper out of START_ARRAY token
Seams that something wrong with my wrapper annotations. How can I fix them?
UPD
When I send
{
"user": [
{
"name": "Bob",
"status": "single"
},
{
"name": "Mike",
"status": "married"
}
]
}
all works fine. But I need this format
[
{
"name": "Bobby",
"status": "single"
},
...
]
UPD
Jersey Client code
HttpAuthenticationFeature authenticationFeature = HttpAuthenticationFeature.basic("user", "secret");
Client client = ClientBuilder
.newClient()
.register(authenticationFeature)
.register(JacksonFeature.class);
WebTarget target = client.target("http://localhost:8080/server/");
UserListWrapper entity;
Response resp;
resp = target.queryParam("u", "info")
.path("/rest/users")
.request()
.accept(APPLICATION_JSON)
.get();
entity = resp.readEntity(UserListWrapper.class);

Forget the UserListWrapper wrapper then. List<User> is perfect for the JSON array ( [] ) format. If you add the wrapper class, then yes you will need the extra JSON object layer ( {} ). This:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response createBook(List<User> users) {
is supported just fine (at least with Jackson - which you are using).
UPDATE
If the response from the server is coming as a JSON array, then you can still deserialize it as a List<User>. For example
WebResource resource = client.resource("...");
List<User> users = resource.get(new GenericType<List<User>>(){});
See this related post
UPDATE 2
Since you are using the JAX-RS 2 client API, you can use the overloaded readEntity, which accepts a GenericType argument also
List<User> user = response.readEntity(new GenericType<List<User>>(){});

Related

How to deserialize JSON with RestTemplate when the request body is either a list or an object?

I am trying to deserialize JSON from consuming an API.
However the JSON body coming from the API is not consistent. Sometimes it comes as a list, and sometimes as a single item.
Example:
"Charge": [
{
"ChargeType": "EXPRESS 12:00",
"ChargeAmount": 0.0
},
{
"ChargeCode": "YK",
"ChargeType": "12:00 PREMIUM",
"ChargeAmount": 0.0
},
]
And in another case:
"Charge": {
"ChargeType": "EXPRESS",
"ChargeAmount": 8.5
}
I am using RestTemplate and DTOs.
My DTO is built like this.
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Charges {
#JsonProperty(value = "Currency")
private String currency;
#JsonProperty(value = "Charge")
private List<Charge> charges;
}
This fails on the case when it comes as an object:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList<Charge>` out of START_OBJECT token
Is there a way I can solve this without creating my Custom JSON Converter?
And if I have to create it, how can I do it?
Solved by using:
#JsonProperty(value = "Charge")
#JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Charge> charges;

How to parse the JSON returned by a REST API call into a collection of objects in JAX-RS?

I am fairly new to JAX-RS so bear with me on this question. I'm trying to consume a REST API using JAX-RS framework. In particular I am trying to invoke a HTTP GET method on a resource where the response entity will be in JSON format. Up until now I can parse the returned JSON into a customized class with the following code snippet;
WebTarget target = client.target(url);
Builder builder = target.request(MediaType.APPLICATION_JSON);
myClass obj = builder.get(myClass.class);
However, in my latest GET request the JSON return will be best abstracted as a collection of objects. I know in .NET this can be done fairly easily with
JsonConvert.DeserializeObject<List<myClass>>
but how could I do that in JAX-RS? Thanks in advance.
EDIT:
I model my code after the solution in How to get list<String> as response from jersey2 client
WebTarget target = client.target(url);
Builder builder = target.request(MediaType.APPLICATION_JSON);
builder.header(X_OCTOPUS_APIKEY_NAME, apiKey);
Response serviceResponse = builder.get(Response.class);
List<myType> objects = serviceResponse.readEntity(new GenericType<List<myType>>() {});
However the objects returned is always null. To verify the REST API call actually return a valid JSON value I replace the last line with:
String strDate = serviceResponse.readEntity(String.class);
It is confirmed with the following JSON return:
[
{
"Id": "Users-267",
"Username": "mdamon#mydomain.com",
"DisplayName": "Damon, Matt",
"IsActive": true,
"IsService": false,
"EmailAddress": "mdamon#mydomain.com",
"IsRequestor": false,
"Links": {
"Self": "/api/users/Users-267",
"Permissions": "/api/users/Users-267/permissions",
"ApiKeys": "/api/users/Users-267/apikeys{/id}{?skip}",
"Avatar": "https://www.gravatar.com/avatar/94324e7c54a9a5f9d103b2a709863fc3?d=blank"
}
},
{
"Id": "Users-2101",
"Username": "baffleck#mydomain.com",
"DisplayName": "Affleck, Ben",
"IsActive": true,
"IsService": false,
"EmailAddress": "baffleck#mydomain.com",
"IsRequestor": false,
"Links": {
"Self": "/api/users/Users-2101",
"Permissions": "/api/users/Users-2101/permissions",
"ApiKeys": "/api/users/Users-2101/apikeys{/id}{?skip}",
"Avatar": "https://www.gravatar.com/avatar/11edd32712facde9a7d3dd4445a4abe9?d=blank"
}
},
...
]
So for reason the JSON is not being parsed at a collection of my custom type. One extra piece of information is my custom is defined as follows:
#XmlRootElement
public class myType {
String DisplayName;
String EmailAddress;
public myType() {
super();
}
public void setDisplayName(String displayName) {
DisplayName = displayName;
}
public String getDisplayName() {
return DisplayName;
}
public void setEmailAddress(String emailAddress) {
EmailAddress = emailAddress;
}
public String getEmailAddress() {
return EmailAddress;
}
}
I only include the DisplayName and EmailAddress field of the JSON in my custom type because I don't need all the other data, in case that matters. Can anyone tell me why it is not being parsed? Thanks

ibm mobilefirst Adapter - convert JSONObject to POJO class

Anyone knows - How to convert JSONObject to POJO class?
I have created an Adapter which i would like to convert it to Pojo before i send it to Client.
1) my ResourceAdapterResource.java (Adapter)
#POST
#Path("profiles/{userid}/{password}")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public JSONObject getStatus(#PathParam("userid") String userid, #PathParam("password") String password) throws IOException {
Map<String, Object> maps = new HashMap<String,Object>();
map.put("userid", userid);
map.put("password",password);
// json Object will get the value from SOAP Adapter Service
JSONObject obj = soapAdapterService(maps);
/** Question here, how to add to POJO.. I have code here but not work, null values**/
// set to Object Pojo Employee
Employee emp = new Employee();
emp.setUserId(String.valueOf(obj.get("userId")));
emp.setUserStatus((String.valueOf(obj.get("userStatus")));
// when I logging its show Empty.
logger.info("User ID from service : " + emp.getUserId());
logger.info("Status Id from service : " + emp.getUserStatus());
return obj;
}
2.) Pojo Class - Employee
import java.io.Serializable;
#SuppressWarnings("serial")
public class Employee implements Serializable{
private String userid;
private String userStatus;
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid= userid;
}
public String getUserStatus() {
return userStatus;
}
public void setUserStaus(String userStatus) {
this.userStatus= userStatus;
}
}
When I tested using Swagger - MobileFirst Console restful testing, it return the JsonObject with successfully return Body with data from the services.
But when i check log info ( message.log ) - server logs, the status is null.
User ID from service : null
Status Id from service : null
Seems its JSON Java IBM API , does it have ObjectMapper like Jackson API to map the JsonObject to POJO Class.
Results from Swagger
{
"statusReason": "OK",
"responseHeaders": {
"Content-Length": "1849",
"Content-Language": "en-US",
"Date": "Thu, 23 Mar 2017 01:40:33 GMT",
"X-Powered-By": "Servlet/3.0",
"Content-Type": "text/xml; charset=utf-8"
},
"isSuccessful": true,
"responseTime": 28,
"totalTime": 33,
"warnings": [],
"Envelope": {
"soapenv": "http://schemas.xmlsoap.org/soap/envelope/",
"Body": {
"checkEmployeeLoginResponse": {
"a": "http://com.fndong.my/employee_Login/",
"loginEmployeeResp": {
"Employee": {
"idmpuUserName": "fndong",
"Status": "A",
"userid": "fndong",
"Password": "AohIeNooBHfedOVvjcYpJANgPQ1qq73WKhHvch0VQtg#=",
"PwdCount": "1",
"rEmail": "fndong#gmail.com"
},
"sessionId": "%3F",
"statusCode": "0"
}
}
}
},
"errors": [],
"info": [],
"statusCode": 200
}
Then I followed your suggestion to cast to String:
String objUserId = (String) objectAuth.get("userid");
The Results still null, does it require to indicate the json restful result by call the body function "loginEmployeeResp", because the data JSon Object are from service SOAP.
Clearly your String.valueOf(obj.get("userId")) is returning null or empty, so the question is, which part of it?
You can log obj.get("userId") and see if that is empty, in which case the response doesn't contain what you expect.
But I suspect the issue is the String.valueOf() conversion not doing what you expect. It looks like the JSONObject in MobileFirst is com.ibm.json.java.JSONObject, and when I search on that, the example I found simply casts to String:
emp.setUserId((String) obj.get("userId"));
Edit: now that you've added the Swagger results, I'd say your obj.get("userId") probably is returning null itself. Did you check that?
For one thing, "userId" isn't "userid". The capitalization matters.
But more importantly, "userid" is nested deep in the JSON, so I don't think just getting it from the top level JSONObject is going to work. I think you'll have to do something like:
JSONObject envelope = (JSONObject) obj.get("Envelope");
JSONObject body = (JSONObject) envelope.get("Body");
JSONObject response = (JSONObject) body.get("checkEmployeeLoginResponse");
JSONObject resp = (JSONObject) response.get("loginEmployeeResp");
JSONObject employee = (JSONObject) resp.get("Employee");
emp.setUserId((String) employee.get("userid"));
emp.setUserStatus((String) employee.get("status"));
(Regrettably, with that particular IBM JSON4J, I don't think there's a way to do a more automatic unmarshalling of JSON into Java objects.)

gson model for json array without key

I have the following json from our customer:
{
"id": 1234,
"delivery_date": 1234567890,
"actions": [
[ "foo", true],
[ "bar", true]
],
"customer": {
"id": 12345,
"company": "",
"firstname": "John",
"lastname": "Smith",
"action": ["dothis", true]
},
"childs": [ 123abc2132312312,11232432943493]
}
I want to parse the "actions" array as a List< Actions> actionList and the single "action" as Action action.
With
class Action {
String action;
boolean yesno;
}
And the childs Array as List< Child> childs with
class Child{
String id
}
Is that possible without the json keys?
Edit:
Your action class is ok, i mis-read slightly.
Add a complete class:
class Delivery {
Int32 id;
Int32 delivery_date;
list<Action> actions;
Customer customer;
list<Int32> childs;
}
actions will be parsed as a paramtere inside, as will childs.
Then you need to create a Customers class too, which is part of this. (or exclude it, and GSON will ignore it)
This will populate the ints into childs and Actions into actions.
If indeed, childs is alphanumeric, then just change it to String.
You can then access it via,
Delivery delivery = GSON ... etc
var x = delivery.actions; // Actions
var y = delivery.childs; // Childs
I solved it my self with a custom deserializer. Thanks to dzsonni for the hint.
In the Gson root class:
private ArrayList<Action> parcel_actions = new ArrayList<Action>();
the action class
class Action {
String action;
boolean yesno;
}
the deserializer:
public class ActionDeserializer implements JsonDeserializer<ArrayList<Action>> {
#Override
public ArrayList<Action> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
ArrayList<Actions> list = new ArrayList<Action>(){};
if(json.getAsJsonArray().get(0).isJsonPrimitive()){
String action = json.getAsJsonArray().get(0).getAsString();
boolean doIt = json.getAsJsonArray().get(1).getAsBoolean();
list.add(new Action(action, doIt));
}
else {
for(JsonElement element : json.getAsJsonArray()) {
String action = element.getAsJsonArray().get(0).getAsString();
boolean doIt = element.getAsJsonArray().get(1).getAsBoolean();
list.add(new Action(action, doIt));
}
}
return list;
}
}
then just add it to your gson
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(new TypeToken<ArrayList<Action>>(){}.getType(), new ActionsDeserializer());
Gson gson = builder.create();

JSON serialization with root element does not work in RestEasy/Jettison/JBossAS7

I am desperately looking for a way to make JSON serialization with root element to work on JBoss AS 7.1 with RestEasy and Jettison provider enabled.
Although, according to RestEasy documentation, returning of the JSON root element should work, I never retrieve when requesting a REST servlet.
I use an Object Factory:
#XmlRegistry
public class ObjectFactory {
private final static QName _NotificationList_QNAME = new QName("xxx:xxx:xxx", "notificationList");
public NotificationList createNotificationList() {
return new NotificationList();
}
#XmlElementDecl(namespace = "xxx:xxx:xxx", name = "notificationList")
public JAXBElement<NotificationList> createNotificationList(NotificationList value) {
return new JAXBElement<NotificationList>(_NotificationList_QNAME, NotificationList.class, null, value);
}
}
With the following XML object:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "NotificationList", namespace = "xxx:xxx:xxx:xxx", propOrder = {
"any"
})
#XmlRootElement (name = "notificationList" )
public class NotificationList {
#XmlAnyElement(lax = true)
protected List<Object> any;
#XmlElement (name="notificationList")
public List<Object> getAny() {
if (any == null) {
any = new ArrayList<Object>();
}
return this.any;
}
}
I expect a notification list to be returned with root element "notificationList" but I don't get it. I use Jettison provider by default but also switched to Jackson. Both do not work for me.
Maybe it is worth mentioning, the REST method is not returning the object itself but passes a AsynchronousResponse to another object which processes and eventually returen the JSON object bacck to I use AsynchronousResponse when creating the response
Edit:
Some more info on the classes actually using NotificationList:
The following REST class consumes a NotificationChannel class (not of interest here) and passes an Asynchronous Response obejct to another classe. This response object eventually returns the NotificationList. In a simplified way, as follows:
#Path("/notificationchannel/v1")
public class NotificationChannelService {
#POST
#Path("/{userid}/channels")
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Mapped(namespaceMap = {
#XmlNsMap(namespace = "XXXX:XXXX:XXXX:XXXX", jsonName = "notificationChannel")
})
public void createNotificationChannel(
final #Suspend(10000) AsynchronousResponse response,
final JAXBElement<NotificationChannel> ncParam,
#PathParam("userid") String userID) {
NotificationManager nMan = new NotificationManager(resp);
}
}
The response is created and returned as follows:
public class NotificationManager {
public NotificationManater(AsynchronousResponse resp){
//dostuff
notificationList = objectFatory.creatNotificationList();
//add notification object (also defined int ObjectFactory)
notificaitonList.addObject(messageNotification)
notificaitonList.addObject(statusNotification)
notificaitonList.addObject(inviteNotification)
//dostuff
resp.setResponse(Response.created(UriBuilder.fromUri(nc.getResourceURL()).build())
.entity(notificationList)
.type(MediaType.APPLICATION_JSON)
.build());
}
}
On client side, i expect the following response:
{"notificationList": {
"inboundMessageNotification": {"inboundMessage": {
"destinationAddress": "tel:+19585550100",
"inboundMMSMessage": {"subject": "Who is RESTing on the beach?"},
"link": {
"href": "http://example.com/exampleAPI/v1/messaging/inbound/subscriptions/sub123",
"rel": "Subscription"
},
"messageId": "msg123",
"resourceURL": "http://example.com/exampleAPI/v1/messaging/inbound/registrations/reg123/messages/msg123 ",
"senderAddress": "tel:+19585550101"
}},
"presenceNotification": {
"callbackData": "1234",
"link": {
"href": "http://example.com/exampleAPI/v1/presence/tel%3A%2B19585550101/subscriptions/presenceSubscriptions/ tel%3A%2B19585550100/sub001",
"rel": "PresenceSubscription"
},
"presence": {"person": {"mood": {"moodValue": "Happy"}}},
"presentityUserId": "tel:+19585550100",
"resourceStatus": "Active"
}
}}
But i do get this (no RootElement name, no notification object name):
{
{
"destinationAddress": "tel:+19585550100",
"inboundMMSMessage": {"subject": "Who is RESTing on the beach?"},
"link": {
"href": "http://example.com/exampleAPI/v1/messaging/inbound/subscriptions/sub123",
"rel": "Subscription"
},
"messageId": "msg123",
"resourceURL": "http://example.com/exampleAPI/v1/messaging/inbound/registrations/reg123/messages/msg123 ",
"senderAddress": "tel:+19585550101"
},
{
"callbackData": "1234",
"link": {
"href": "http://example.com/exampleAPI/v1/presence/tel%3A%2B19585550101/subscriptions/presenceSubscriptions/ tel%3A%2B19585550100/sub001",
"rel": "PresenceSubscription"
},
"presence": {"person": {"mood": {"moodValue": "Happy"}}},
"presentityUserId": "tel:+19585550100",
"resourceStatus": "Active"
}
}
I faced the exact same issue and the problem is that the json provider based on Jackson (resteasy-jackson-provider) is actually taking over the serialization (due to the implicit module dependency). What I did was to use a specific deployment descriptor META-INF/jboss-deployment-structure.xml with the following content.
<jboss-deployment-structure>
<deployment>
<exclusions>
<module name="org.jboss.resteasy.resteasy-jackson-provider" />
</exclusions>
<dependencies>
<module name="org.jboss.resteasy.resteasy-jettison-provider" />
</dependencies>
</deployment>
</jboss-deployment-structure>
It will force the container to switch to the jettison provider for your application.