How can I convert the JSON string like this:
{ "summary": {
"totalMR":4.599000000000903E12,
"totalMA":1.9174920000386694E11,
"totalQA":5.1111111181E9,
"totalQR":1.000020666115264E11
},
"result": [{},{}],
"success":"true",
"total":49
}
to a Java object. I went through many similar posts and implemented constructors but couldn't find the proper explanation of why I'm unable to De-serialize the JSON.
Am I doing anything wrong?
My Class:
public class expResponse {
private String success;
private String total;
private ArrayList<LinkedHashMap<String,Object>> result;
private LinkedHashMap<String,SummaryResponse> summary;
// Constructor: public expResponse(){}
// Getter and Setter
}
public class SummaryResponse {
private Float totalQR;
private Float totalQA;
private Float totalMR;
private Float totalMA;
public SummaryResponse(){}
// Setter and Getter
}
My Code:
private expResponse processResult(String result) throws IOException{
ObjectMapper objectMapper = new ObjectMapper();
expResponse expResponseObj =
objectMapper.readValue(result, expResponse.class);
return expResponseObj;
The json you posted would not deserialize into a map of SummaryResponse objects, but rather an individual SummaryResponse object. To make your binding work, you would have to have json that looked something like this:
{
...
'summary': {
'summary1': {"totalMR":4.599000000000903E12,"totalMA":1.9174920000386694E11,"totalQA":5.1111111181E9,"totalQR":1.000020666115264E11}
'summary2': {"totalMR":4.599000000000903E12,"totalMA":1.9174920000386694E11,"totalQA":5.1111111181E9,"totalQR":1.000020666115264E11}
}
...
}
Alternatively, if you need to make your Java class conform to the json you provided, you simply need to change the declaration of summary:
private SummaryResponse summary;
Field summary in your json is an object of type SummaryResponse and not a LinkedHashMap.
public class ExpResponse {
private String success;
private String total;
private ArrayList<LinkedHashMap<String,Object>> result;
private Summary summary;
}
I don't think you have a problem in the code. Your input fails because it is not in the correct format. If you try to write the same values from an object with the same values to string you get something like:
{
"success":"true",
"total":"49",
"result":null,
"summary":{
"one_summary":{
"totalQR":2000.0,
"totalQA":1500.0,
"totalMR":1000.0,
"totalMA":500.0
}
}
}
And the major difference is the one summary. This is because summary is a map and maps need a key for each entryset. That means that summary is your map which has a one_summary key.
Is it the SummaryResponse that can't be deserialised?
I guess your attributes should have the same name "totalMR", "totalMA"....
or you should use an annotation JsonProperty(value="totalMR") and so on.
Related
I have a Pojo class with all numeric fields
public class Pojo {
private long field1;
private long field2;
private long field3;
private long field4;
private long field5;
private double field6;
private double field7;
private double field8;
private double field9;
}
And there is a list of Pojo, I want map this list to one Pojo object which will contain in its field the of pojos foe, list. I mean someething like this :
public static void main(String[] args) {
List<Pojo> pojoList = getPogoList();
Pojo pojoInSum = reduceAllFields(pojoList);
}
What is the simplest way to reduce all fields of pojos from list without reflection?
You could use the Stream#reduce method:
public void reducePojoList() {
PojoReduce pojoReduce = new PojoReduce();
List<Pojo> pojoList = Arrays.asList(
new Pojo(3L, 4.0),
new Pojo(6L, 1.1));
Optional<Pojo> reducedPojo = pojoList.stream().reduce(this::combine);
reducedPojo.ifPresent(System.out::println);
}
private Pojo combine(Pojo pojo1, Pojo pojo2) {
return new Pojo(
pojo1.getLongField() + pojo2.getLongField(),
pojo1.getDoubleField() + pojo2.getDoubleField()
);
}
You would have to update the combine method for every field you add though. You'd also be creating a lot of new objects.
The simplest way is to write a method in that pojo. Because if you are modeling a thing in a class you should expose behavior and not data.
But I doubt that is what you are looking for so you might want to look at reflection.
Basically you retrieve all the fields of a class, get the values for the instance and then sum them in a loop or stream.
I have some nested classes in Java, simplified here. Getters and setters exist.
Example
public class Planet {
#JsonProperty("name")
private String name;
#JsonProperty("moons")
private List<Moon> moons;
}
public class Moon {
#JsonProperty("moonname")
private String name;
#JsonProperty("craters")
private int craters;
}
I want to be able to deserialize the records on mongo (following this same structure) to java objects on the rest controller, specifically the HTTP GET request.
#RestController
#RequestMapping("/planets")
public class PlanetController {
#Autowired
private PlanetService planetService;
#RequestMapping("/")
public List<Planet> getAllPlanets() {
//Need to deserialize here
return planetService.getAll();
}
#RequestMapping("/{name}")
public Planet getItemsWithName(#PathVariable("name") String name) {
//deserialize here
return planetService.getEntryWithName(name.toLowerCase());
}
PlanetService.getAll() is expecting return type of List. getEntryWithName() is expecting return type of Planet.
How can I loop the results in the getAll() so I can deserialize them before they are returned?
Using Jackson's object mapper, I can do the serialization of a Java object to a JSON object.
ObjectMapper mapper = new ObjectMapper();
try {
mapper.writeValue(new File("target/mars.json"), mars);
} catch (IOException e) {
e.printStackTrace();
}
I can probably use readValue for the opposite process but I don't know how to loop the results.
I will appreciate the help. Let me know if something is not clear.
public List<Planet> getAllPlanets() {
List<Planet> planets = planetService.getAll();
String jsonString = new ObjectMapper().writeValueAsString(planets);
return planets;
}
I've tried so many ways, but without success to parse this Json to a Java Object using Gson library:
"return":{
"48388":{
"status":"canceled",
"operations":{
},
"created":"138232386",
"price":"12.50000",
"volume":"50.00000000",
"pair":"btc_brl",
"type":"buy"
},
"51714":{
"status":"canceled",
"operations":{
},
"created":"1365465421706",
"price":"1500.00000",
"volume":"0.10000000",
"pair":"btc_brl",
"type":"buy"
},
"48754":{
"status":"canceled",
"operations":{
},
"created":"1383237058",
"price":"600.00000",
"volume":"0.50000000",
"pair":"btc_brl",
"type":"buy"
}
"success":1
}
There is a lot of topics about this, but none of them cover this type of json mapping.
I'm convinced that there is a simple way to do that, any ideas? Thanks!
EDIT:
I'm trying this:
public class Test {
#SerializedName("return")
public Return1 _return;
}
public class Return {
public List<Map<String, Order>> order;
}
EDIT:
public class Order {
#SerializedName("id")
private int idOrder;
private String status;
private String created;
private String price;
private String volume;
private String pair;
private String type;
private List<Operations> operations;
// All the gets and sets here..
}
Gson doesn't initialize my order object. The order object is always null. I can't find the correct way to implement this mapping.
After a long battle I was able to solve using this solution:
public void deserialize() {
Gson gson = new Gson();
// For isr read InputStreamReader
Map<String, Object> map = gson.fromJson(isr, Map.class);
System.out.println(map.get("success"));
Map<String, Object> map2 = (Map<String, Object>) map.get("return");
// Show the contents of return
System.out.println(map2);
}
After that I used an Entry object to iterate and set the values of Order.
Thanks!
I'm having problem to assign json data into java class.Please do help anyone,
My java class is like,
public class ListofGridRecords<T> {
public int Totalrecords;
public List<T> GridRecords;//using TraderTransaction class.
}
and TraderTransaction class is,
public class TraderTransaction {
public Date AddedTime;
public String TransactId;
public TransactStatus Status;
public String OtherPartyAccountNo;
public Double AmountPaid;
public Double AmountRecieved;
public Double ClosingBalance;
public TransactionTypes TransType;
public String Narration;
public TraderTransaction() {
super();
}
}
and my json conversion function look like,
JsonObject returndata = JsonObject.parse(responseString);
String operationresult = returndata.get("OperationResult").toString();
if (Result.values()[Integer.parseInt(operationresult)] == Result.Success) {
Gson gson = new Gson();
#SuppressWarnings("unchecked")
ListofGridRecords<TraderTransaction> traderlist =
gson.fromJson(returndata.get("ResultData").toString(), ListofGridRecords.class);
Log.i("LIST DATA:", "" + traderlist);
for (TraderTransaction trader: traderlist.GridRecords) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(TRANS_FIRST_COLUMN, currentformatter.format(trader.AddedTime));
map.put(TRANS_SECOND_COLUMN, trader.TransactId);
map.put(TRANS_THIRD_COLUMN, trader.OtherPartyAccountNo);
map.put(TRANS_FOURTH_COLUMN, trader.AmountPaid.toString());
map.put(TRANS_FIFTH_COLUMN, trader.AmountRecieved.toString());
map.put(TRANS_SIXTH_COLUMN, OpenOrClosed.values()[Integer.parseInt(trader.TransType.toString())].toString());
list.add(map);
}
}
I'm getting conversion error at for (TraderTransaction trader : traderlist.GridRecords).
My Json data look like,
{
"Messages":"RESULTS_RETRIEVAL_SUCCESSFULL",
"OperationResult":0,
"ResultData":{
"GridRecords":[
{
"AddedBy":"Distributor-9787457361-Rathinavel",
"AddedTime":"2013-04-12T16:26:24.0140117",
"AmountPaid":0.0,
"AmountRecieved":10000.0,
"ClosingBalance":10000.0,
"Narration":null,
"OtherPartyAccountNo":"0102849015327675",
"Status":2,
"TransType":2,
"TransactId":"TDRF483679051236"
},
{
"AddedBy":"Distributor-9787457361-Rathinavel",
"AddedTime":"2013-04-12T16:20:54.8681857",
"AmountPaid":0.0,
"AmountRecieved":0.0,
"ClosingBalance":0.0,
"Narration":null,
"OtherPartyAccountNo":"0102849015327675",
"Status":0,
"TransType":2,
"TransactId":"TDRF706925413802"
}
],
"Totalrecords":2
},
"UpdateAvailable":"0"
}
In order to parse your JSON, I'd use a slightly different strategy. As you seem to be interested in parsing only the "ResultData", I'd create classes to wrap the response, very similar to those you have already created, namely:
public class Response {
#SerializedName("ResultData")
public ResultData resultData;
}
and,
public class ResultData {
#SerializedName("GridRecords")
public List<GridRecord> gridRecords;
#SerializedName("Totalrecords")
public int totalrecords;
}
and,
public class GridRecord {
#SerializedName("AddedTime")
public String addedTime;
#SerializedName("TransactId")
public String transactId;
//other fields...
}
and other classes if necessary...
Then, in order to parse your JSON reponse, you just have to do:
Gson gson = new Gson();
Response data = gson.fromJson(responseString, Response.class);
and you'll be able to access any field, for example:
data.resultData.gridRecords.transactId;
Note 1: If you are interested in more fields of the JSON response, you just have to add more fields to your wrap classes, according to the JSON response...
Note 2: I've changed the type of addedTime to String, instead of Date because it throws an exception for unparseable date. Anyway I usually leave the types in the Response objects as simple String and then in the class from where I retrieve the response, I do the correct formatting while creating my objects, for example, when you put the values in your Map...
Note 3: The use of the annotation #SerializedName is interesting to separate the name of a field in the JSON response and in your app, in order to follow Java naming conventions, which your attributes are not following...
Note 4: You shouldn't use public attributes in your classes. It's more recommendable to use private/protected attributes and their correspondent getters and setters...
suppose I've got a collection of people defined like this in JSON.
{
"NOM": "Doe",
"PRENOM": "John",
"EMAIL": "john.doe#email.me",
"VILLE": "Somewhere",
"LIKE1": "Lolcats",
"LIKE2": "Loldogs",
"LIKE3": "Lolwut",
"HATE1": "Bad stuff",
"HATE2": "Bad bad stuff"
}
Is it possible to write a JsonDeserializer that will aggregate and transform LIKE* and HATE* fields into a collection of Liking, set as a property of Person? (Note that there are only LIKE1, LIKE2, LIKE3, HATE1, HATE2.)
The final result properties would be something like:
public class Person {
private final String lastName;
private final String firstName;
private final String email;
private final String town;
private final Collection<Liking> likings;
// c-tor, getters
}
I've already the logic that can deserialize a given LIKE*/HATE* property into a Liking object but I fail to understand to aggregate and add them to a Person liking attribute.
Thx in advance!
It would have been nice if you had some code that showed you began the process of solving this problem yourself. But, here is a sample custom deserializer that does pretty much what you're looking for:
class PersonDeserializer extends JsonDeserializer<Person> {
#Override
public Person deserialize(final JsonParser parser,
final DeserializationContext content) throws IOException,
JsonProcessingException {
final ObjectCodec codec = parser.getCodec();
final JsonNode node = codec.readTree(parser);
final Person person = new Person();
final Iterator<String> fieldNameIter = node.getFieldNames();
while (fieldNameIter.hasNext()) {
final String fieldName = fieldNameIter.next();
if (fieldName.equalsIgnoreCase("EMAIL")) {
person.setEmail(node.get(fieldName).getTextValue());
} else if (fieldName.equalsIgnoreCase("NOM")) {
person.setFirstName(node.get(fieldName).getTextValue());
} else if (fieldName.equalsIgnoreCase("PRENOM")) {
person.setLastName(node.get(fieldName).getTextValue());
} else if (fieldName.equalsIgnoreCase("VILLE")) {
person.setTown(node.get(fieldName).getTextValue());
} else if (fieldName.startsWith("LIKE")) {
person.addLike(Liking.LikingType.LIKE, node.get(fieldName)
.getTextValue());
} else if (fieldName.startsWith("HATE")) {
person.addLike(Liking.LikingType.HATE, node.get(fieldName)
.getTextValue());
}
}
return person;
}
}
It presumes a Liking object similar to this:
public class Liking {
public static enum LikingType {
LIKE, HATE;
}
private LikingType type;
private String value;
// Constructors, getters/setters
}
And some changes to your Person object which I think you can figure out. If you intend to serialize the object to JSON in the same custom format then you will have to write a corresponding JsonSerializer.
Another option, not quite as robust, would be too simply use a map to store the likes and dislikes exactly as is. This solution would omit any explicit mappings for likes/dislikes and utilize the #JsonAny annotation to capture them. In this scheme the Person object would look like this:
public class Person {
private String lastName;
private String firstName;
private String email;
private String town;
#JsonAny
private Map<String, Object> otherProperties;
// Constructors, getters/setters
}
Deserializing your JSON into this modified version of Person will place all unrecognized properties into the hash map, as key-value pairs.
I'm pretty sure you can't do it the way you intend, how about doing it like this:
{
"NOM": "Doe",
"PRENOM": "John",
"EMAIL": "john.doe#email.me",
"VILLE": "Somewhere",
"likings": ["Lolcats", "Loldogs", "LIKE3": "Lolwut", "Bad stuff", "Bad bad stuff" ]
}