Deserialize json with different object types - java

I get the following json from a httpresponse
{
"result": "success",
"team_registration": {
"current_status": "executed",
"expiration_time": "2012-07-18T21:29:43Z",
"id": 609,
"team_id": 50,
}
}
How do I retreive the "result" as a string and the "team_registration" as a POJO (in Android) with Jackson?
Currently I have this:
HttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
String json = EntityUtils.toString(entity);
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
});
result = (String) map.get("result");
resultRegistration = (Registration) map.get("team_registration");
Registration class:
package be.radarwerk.app.model;
import java.io.Serializable;
import java.util.Date;
import org.codehaus.jackson.annotate.JsonIgnore;
public class Registration implements Serializable { // Todo implements parceable?
private static final long serialVersionUID = 1L;
private int id;
private String currentStatus;
private Date expirationTime;
#JsonIgnore
private Volunteer volunteer;
#JsonIgnore
private Team team;
public Registration() {
}
public Registration(int id, String currentStatus, Volunteer volunteer,
Team team) {
super();
this.id = id;
this.currentStatus = currentStatus;
this.volunteer = volunteer;
this.team = team;
}
public int getId() {
return id;
}
public String getCurrentStatus() {
return currentStatus;
}
public Volunteer getVolunteer() {
return volunteer;
}
public Team getTeam() {
return team;
}
public Date getExpirationTime() {
return expirationTime;
}
}
"result" as String works fine but for the "registration_moment" I get this exception:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to Registration
I also tried casting it to a String in the same way as "result" and doing mapper.readValue on that string.
No success.
Any tips?

Your class should be deserialized automatically if you modify it like this (Note! Jackson 2.1+ required):
#JsonIgnoreProperties("team_id")
#JsonNamingStrategy(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy)
public class Registration implements Serializable
{
private static final long serialVersionUID = 1L;
private int id;
private String currentStatus;
private Date expirationTime;
#JsonIgnore
private Volunteer volunteer;
#JsonIgnore
private Team team;
public Registration() {
}
// other code
}
Then, to deserialize in your code:
Registration registration;
final JsonNode node = mapper.readTree(json);
if (node.get("result").textValue().equals("success"))
registration = mapper.readObject(node.get("team_registration").traverse(),
Registration.class);

Your approach seems a bit odd to me. You should really be using the Android JSONObject class, that's what it's there for. Once you have a JSONObject (or JSONArray), you will need to iterate over it if you want to move elements into a different data structure, but that's very likely unnecessary.
In any event, here's some code (using android-query) to get you to a JSONObject:
String url = "whatever you want";
aq.ajax(url, JSONArray.class, new AjaxCallback<JSONArray>() {
#Override
public void callback(String url, JSONArray json, AjaxStatus status) {
if (json == null) {
Toast.makeText(context, "Failed to retrieve JSON", Toast.LENGTH_SHORT);
}
else {
try {
JSONObject general = json.getJSONObject(0);
...
}
}
}
});

Related

How to keep the JSON's order preserved while sending to frontend application from SpringBoot Application's service?

I'm developing a springboot application.
I've a class with the following fields
class MyClass
{
String s1;
String s2;
String s3;
String s4;
//getters setters constructors
}
I'm calling an API which in turn calls a service.
public String myService()
{
JSONArray arr1 = new JSONArray();
for (Items item : itemsList)
{
JSONObject itemObj = new JSONObject();
itemObj.put("s1","Value1");
itemObj.put("s2","Value2");
itemObj.put("s3","Value3")
itemObj.put("s4","Value4");
arr1.put(itemObj);
}
JSONObject out = new JSONObject();
out.put("total_Items", arr1);
return out.toString(); // this is org.json.JSONObject
}
This way I'm able to get the excel with the reordered members as the columns when a button is clicked at the frontend angular app.
What I want is the order of the the members in the columns remains preserved when exporting into an excel sheet.
s1|s2|s3|s4 //as per the above example
I've many other services as well, which return different types of Objects(apart from the MyClass mentioned here) so I wanted to return the elements in the order defined (as per the order of members in the class) from the backend itself.
I know that JSON does not allow us to preserve the order as it internally uses a HASHMAP.
Is there a way to return a JSON response such that the order remains same as that of the class members?
I also tried using GSON in the below way.
public String myService()
{
MyClass itemsArray[] = new MyClass[itemsList.size()];
int i=0;
for (Items item : itemsList)
{
MyClass itemObj = new MyClass();
itemObj.setS1("Value1");
itemObj.setS2("Value2");
itemObj.setS3("Value3")
itemObj.setS4("Value4");
itemsArray[i]=itemObj;
}
Gson gson = new Gson();
return gson.toJson(itemsArray); // this is java.lang.String
}
In this scenario I'm able to get the API response(on POSTMAN) with the elements in ordered fashion but when exporting on the frontend angular app it freezes at the downloading screen.
I tried doing conversion to JSONObject and other things randomly but was not able to make the code work properly.
Is there anyway the problem can be resolved at the backend...or something needs to be done at the frontend only?
Thanks in advance.
If you want to do using DataStructure use LinkedHashMap as given below. It will serialize in inserted order.
public static void main(String args[]){
ObjectMapper mapper = new ObjectMapper();
Map<String, String> itemObj = new LinkedHashMap<>();
itemObj.put("s91","Value1");
itemObj.put("s2","Value2");
itemObj.put("s3","Value3");
itemObj.put("s4","Value4");
try {
String jsonString = mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(itemObj);
System.out.println(jsonString);
}
catch (IOException e) {
e.printStackTrace();
}
}
{
"s91" : "Value1",
"s2" : "Value2",
"s3" : "Value3",
"s4" : "Value4"
}
If you want to serialize in sorted order the use TreeMap, it will serialize in sorted key
Map<String, String> itemObj = new TreeMap<>();
...
{
"s2" : "Value2",
"s3" : "Value3",
"s4" : "Value4",
"s91" : "Value1"
}
This can be done using Jackson library using the #JsonPropertyOrder annotation.
You can define the order of elements as given below above class
#JsonPropertyOrder({ "s3", "s2", "s1", "s4"})
Refer to below a working example
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.istack.NotNull;
import java.io.IOException;
import java.util.UUID;
#JsonPropertyOrder({ "id", "password", "name", "email", "enabled" })
public class UserResource {
private UUID id;
#NotNull
private String name;
#NotNull
private String email;
private boolean enabled;
private String password;
public UserResource(UUID id, String name, String email, boolean enabled, String password) {
this.id = id;
this.name = name;
this.email = email;
this.enabled = enabled;
this.password = password;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static void main(String args[]){
ObjectMapper mapper = new ObjectMapper();
try {
UserResource student = new UserResource(UUID.randomUUID(), "sheel", "sheel#c4c.com",true, "$$$$$$%%##^^$DSGHHH");
String jsonString = mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(student);
System.out.println(jsonString);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
and output as given below
{
"id" : "fbfcd21d-731e-4acb-9fec-90a499e47cc9",
"password" : "$$$$$$%%##^^$DSGHHH",
"name" : "sheel",
"email" : "sheel#c4c.com",
"enabled" : true
}

Java Spring Boot can't read result from keys whose value is a hashmap

I have a simple server reads all logs from mongodb, but some data in the db has different format for their result property.
one is whose result property has a value like a hashmap:
{
"event_name" : "Transfer",
"result" : { "_from" : "0x928c9af0651632157ef27a2cf17ca72c575a4d21",
"_value" : "1111",
"_to" :"0x143449e55cdd2a5bae081f041650ba9089812a95" },
"transaction_id":"c2c986a96a0cfa7fc96619733449fd88c9d685bf704a50d07baef74f6
}
then for the result property, it returns an empty result for me,
but if the result property is like this, which is just like an array:
"result" : ["0x928c9af0651632157ef27a2cf17ca72c575a4d21", "1111", "0x143449e55cdd2a5bae081f041650ba9089812a95"],
then it will outputs the result value.
The thing is it has both format in the mongodb, is there any way to handle both of the 2 different format of result property?
import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
#Document(collection = "eventLog")
public class EventLogEntity implements Serializable {
private static final long serialVersionUID = -70777625567836430L;
#Id
private String id;
#Field(value = "block_number")
#JsonProperty(value = "block_number")
private long blockNumber;
#Field(value = "block_timestamp")
#JsonProperty(value = "block_timestamp")
private long blockTimestamp;
#Field(value = "contract_address")
#JsonProperty(value = "contract_address")
private String contractAddress;
#Field(value = "event_name")
#JsonProperty(value = "event_name")
private String entryName;
#Field(value = "result")
#JsonProperty(value = "result")
private JSONArray resultJsonArray;
#Field(value = "transaction_id")
#JsonProperty(value = "transaction_id")
private String transactionId;
public EventLogEntity(long blockNumber, long blockTimestamp, String contractAddress,
String entryName, JSONArray resultJsonArray, String transactionId) {
this.blockNumber = blockNumber;
this.blockTimestamp = blockTimestamp;
this.contractAddress = contractAddress;
this.entryName = entryName;
this.resultJsonArray = resultJsonArray;
this.transactionId = transactionId;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public long getBlockNumber() {
return blockNumber;
}
public void setBlockNumber(long blockNumber) {
this.blockNumber = blockNumber;
}
public long getBlockTimestamp() {
return blockTimestamp;
}
public void setBlockTimestamp(long blockTimestamp) {
this.blockTimestamp = blockTimestamp;
}
public String getContractAddress() {
return contractAddress;
}
public void setContractAddress(String contractAddress) {
this.contractAddress = contractAddress;
}
public String getEntryName() {
return entryName;
}
public void setEntryName(String entryName) {
this.entryName = entryName;
}
public JSONArray getResultJsonArray() {
System.out.println(resultJsonArray.toString());
return resultJsonArray;
}
public void setResultJsonArray(JSONArray resultJsonArray) {
this.resultJsonArray = resultJsonArray;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
}
First of all, you have 2 different documents entities, if you really need keep both formats and read one or other, you should one have Entity for each structure.
One entity will be as you described, and the other will have the result property as follows:
public class ResultObject{
private String _from;
private String _value;
private String _to;
//getters, setters & constructor
}
And you reference this ResultObject as property of your other Entity:
public class EventLogEntityWithResultObject implements Serializable{
...
private ResultObject result;
...
}
If you do not need to keep both structures, you could migrate all documents from one structure type to another using MongoDB commands, see this for example: Change document structure in mongodb with the mongo shell

Unable to convert JSON object to Java Object correctly

I am facing an issue while converting an JSON to a Java Object.
My Json is as below
{
"_id":{
"$oid":"5981428cf1aa82a313540b76"
},
"productId":1,
"name":"The Big Lebowski",
"currency":{
"currency":"USD",
"value":40.5
}
}
I am retrieving json as DBObject for Product from the MongoDB database.
DBObject dbObject = productsCollection.findOne(searchQuery);
if(dbObject != null)
{
Product product = (Product) AppUtils.fromDBObject(dbObject, Product.class);
return Optional.of(product);
}
Product is return as
Product[productId = 1, productName= null, currencyPrice = null]
My fromDBObject method in AppUtils.java is as below :
public static Object fromDBObject(DBObject dbObj, Class<?> clazz)
{
String json = dbObj.toString();
return new Gson().fromJson(json, clazz);
}
My POJO is as below :
public class Product
{
private long productId;
private String productName;
private CurrencyPrice currencyPrice;
// getter and setter
}
public class CurrencyPrice
{
private double value;
private String currency;
// getter and setter
}
I am unable to understand where it is going wroing for the DBObject object with json to translate to Product object.
Thanks !
try changing your POJO property names to match
public class Product
{
private long productId;
private String name;
private CurrencyPrice currency;
// getter and setter
}

Parsing JSON data into model objects in Java

I haven't worked with JSON data before, thus the question.
I've the following JSON object in a file.
{
"courses": [
{ "id":998", "name":"Java Data Structures", "teacherId":"375" },
{ "id":"999", "name":"Java Generics", "teacherId":"376" }
],
"teachers": [
{ "id":"375", "firstName":"Amiyo", "lastName":"Bagchi"},
{ "id":"376", "firstName":"Dennis", "lastName":"Ritchie"}
]
}
Here are my model Objects.
public class Course {
private int _id;
private String _name;
private Teacher _teacher;
}
public class Teacher {
private int _id;
private String _firstName;
private String _lastName;
}
My task is to read the JSON Objects and return a list of Model objects.
I've imported the simple.JSON family of jar and here's my code that reads the file.
FileReader reader = new FileReader(path);
JSONParser parser = new JSONParser();
Object obj = parser.parse(reader);
JSONObject jsonObject = (JSONObject) obj;
My question is,
How do I parse the JSON document into my Model objects?
If the input file is JSON but of a different format how do I throw exception/handle the anomaly?
Any help appreciated.
UPDATE I suggest you use JSON parser to parse the data:
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
class Course {
public int _id;
public String _name;
public Teacher _teacher;
private Course(int id, String name, Teacher teacher){
this._id = id;
this._name = name;
this._teacher = teacher;
}
public Course() {
}
}
class Teacher {
public int _id;
public String _firstName;
public String _lastName;
private Teacher(int id, String fname, String lname){
this._id = id;
this._firstName = fname;
this._lastName = lname;
}
public Teacher(){
}
}
public class jsontest {
public static void main(String[] args) throws JSONException, IOException {
// String JSON_DATA = "{\n"+
// " \"courses\": [\n"+
// " { \"id\":\"998\", \"name\":\"Java Data Structures\", \"teacherId\":\"375\" },\n"+
// " { \"id\":\"999\", \"name\":\"Java Generics\", \"teacherId\":\"376\" }\n"+
// "\n"+
// " ],\n"+
// " \"teachers\": [\n"+
// " { \"id\":\"375\", \"firstName\":\"Amiyo\", \"lastName\":\"Bagchi\"},\n"+
// " { \"id\":\"376\", \"firstName\":\"Dennis\", \"lastName\":\"Ritchie\"} \n"+
// " ]\n"+
// "}\n"+
// "";
// read json file into string
String JSON_DATA = new String(Files.readAllBytes(Paths.get("path_to_json_file")), StandardCharsets.UTF_8);
// using a JSON parser
JSONObject obj = new JSONObject(JSON_DATA);
// parse "teachers" first
List<Teacher> listCourses = new ArrayList<Teacher>();
List<JSONObject> listObjs = parseJsonData(obj,"teachers");
for (JSONObject c: listObjs) {
Teacher teacher = new Teacher();
teacher._id = c.getInt("id");
teacher._firstName = c.getString("firstName");
teacher._lastName = c.getString("lastName");
listCourses.add(teacher);
}
// parse "courses" next
List<Course> resultCourses = new ArrayList<Course>();
List<JSONObject> listObjs2 = parseJsonData(obj, "courses");
for (JSONObject c: listObjs2) {
Course course = new Course();
course._id = c.getInt("id");
course._name = c.getString("name");
int teacherId = c.getInt("teacherId");
HashMap<String, Teacher> map = new HashMap<String, Teacher>();
for (Teacher t: listCourses){
map.put(Integer.toString(t._id), t);
}
course._teacher = map.get(Integer.toString(teacherId));
resultCourses.add(course);
}
}
public static List<JSONObject> parseJsonData(JSONObject obj, String pattern)throws JSONException {
List<JSONObject> listObjs = new ArrayList<JSONObject>();
JSONArray geodata = obj.getJSONArray (pattern);
for (int i = 0; i < geodata.length(); ++i) {
final JSONObject site = geodata.getJSONObject(i);
listObjs.add(site);
}
return listObjs;
}
}
Output:
BTW: The json data in the example has one value whose double quotes are not in pairs. To proceed, it must be fixed.
You should try using Jackson as the JSON parsing library instead. There is a lot more support and features that come with it.
In your case, a couple of annotations to map the JSON properties to the Java fields should be sufficient.
https://github.com/FasterXML/jackson-annotations
https://github.com/FasterXML/jackson-databind
UPDATE: Some code, to show just much better this can be done with Jackson.
public class Course {
#JsonProperty("id")
private int _id;
#JsonProperty("name")
private String _name;
#JsonProperty("teacher")
private Teacher _teacher;
// ...public getters and setters
}
public class Teacher {
#JsonProperty("id")
private int _id;
#JsonProperty("firstName")
private String _firstName;
#JsonProperty("lastName")
private String _lastName;
// ...public getters and setters
}
// Container class to conform to JSON structure
public class CoursesDto {
private List<Teacher> teachers;
private List<Course> courses;
}
// In your parser place
ObjectMapper mapper = new ObjectMapper();
FileReader reader = new FileReader(path);
CoursesDto dto = mapper.readValue(reader, CoursesDto.class);
The #JsonProperty annotations tell Jackson what JSON key should be used to deserialize. They are not necessary if the property names match the JSON keys. That means that if you remove the leading underscore from your property names, this would work without annotations. Also, Jackson will default to using public fields and getter/setter methods. This means that you can keep your fields prefixed by _ as long as the getter/setter don't have it (setFirstName(String firstName)).

Getting an error when trying to deserialize a JSON string with GSON

I'm trying to decode a JSON string that's coming from a php script I made that gets results out of my MySQL database. It returns a JSON array.
This is the code for my decoder:
package com.github.viperdream;
import java.lang.reflect.Type;
import java.util.List;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class JSONDecoder {
public static void decodePin(String data){
Gson gson = new Gson();
Type type = new TypeToken<List<Pin>>(){}.getType();
List<Pin> pin = gson.fromJson(data, type);
for (Pin newPin : pin){
Log.d("GSON", newPin.getPinTitle());
}
}
}
This is the Pin object class:
package com.github.viperdream;
public class Pin {
private Integer pinID;
private String pinTitle;
private String pinMessage;
private Integer pinDuration;
private Float pinX;
private Float pinY;
private String pinColor;
private String author;
private Integer pinSQLId;
public Pin(){}
public Pin(int pinID, String pinTitle, String pinMessage, Integer pinDuration, Float pinX, Float pinY, String pinColor, String author, Integer pinSQLId){
this.pinID = pinID;
this.pinTitle = pinTitle;
this.pinMessage = pinMessage;
this.pinDuration = pinDuration;
this.pinX = pinX;
this.pinY = pinY;
this.pinColor = pinColor;
this.author = author;
this.pinSQLId = pinSQLId;
}
public Pin(String pinTitle, String pinMessage, Integer pinDuration, Float pinX, Float pinY, String pinColor, String author, Integer pinSQLId){
this.pinTitle = pinTitle;
this.pinMessage = pinMessage;
this.pinDuration = pinDuration;
this.pinX = pinX;
this.pinY = pinY;
this.pinColor = pinColor;
this.author = author;
this.pinSQLId = pinSQLId;
}
//get ------------------------------------------------------
public int getID(){
return this.pinID;
}
public String getPinTitle(){
return this.pinTitle;
}
public String getPinMessage(){
return this.pinMessage;
}
public Integer getPinDuration(){
return this.pinDuration;
}
public Float getPinX(){
return this.pinX;
}
public Float getPinY(){
return this.pinY;
}
public String getPinColor(){
return this.pinColor;
}
public String getPinAuthor(){
return this.author;
}
public Integer getPinSQLId(){
return this.pinSQLId;
}
//set ------------------------------------------------------
public void setPinID(int pinID){
this.pinID = pinID;
}
public void setPinTitle(String pinTitle){
this.pinTitle = pinTitle;
}
public void setPinMessage(String pinMessage){
this.pinMessage = pinMessage;
}
public void setPinDuration(int pinDuration){
this.pinDuration = pinDuration;
}
public void setPinX(Float pinX){
this.pinX = pinX;
}
public void setPinY(Float pinY){
this.pinY = pinY;
}
public void setPinColor(String pinColor){
this.pinColor = pinColor;
}
public void setPinAuthor(String author){
this.author = author;
}
public void setPinSQLId(Integer pinSQLId){
this.pinSQLId = pinSQLId;
}
}
This is the JSON String that I'm trying to decode:
[
{
"id":"2",
"title":"test1",
"message":"test2",
"duration":"1",
"x":"125",
"y":"754.5",
"color":"red",
"author":"viperdream"
},
{
"id":"3",
"title":"looking for someone",
"message":"i need to go now",
"duration":"1",
"x":"401",
"y":"472.5",
"color":"red",
"author":"viperdream"
},
{
"id":"4",
"title":"test3",
"message":"testing:)",
"duration":"1",
"x":"195",
"y":"512.5",
"color":"red",
"author":"viperdream"
}
]
And this is how I make the Json string in PHP
while($pin = mysql_fetch_assoc($query_exec)) {
$pins[] = $pin;
}
echo json_encode($pins);
Whenever I run my app, it gives me this error:
java.lang.NullPointerException: println needs a message
Anyone knows what I am doing wrong?
If you need any more information, please do ask!
Thanks in advance!
Gson tries to match the JSON element names to your class' field names. In your case, you have id, title, etc. instead of pinId, pinTitle, etc. If Gson finds an element for which it doesn't find a matching field, it skips it, leaving the field null (or whatever default it has).
The element and field names need to be equal.
Alternatively, you could annotate your field with #SerializedName and give it the value you are expecting from the json.
#SerializedName("id")
private Integer pinID;

Categories

Resources