How to expand and object in JSON body? - java

I have the next classes to have the appropriate json bodies:
public class MyResponse {
private String meta;
private String info;
private String respOne;
//...
}
And
public class MyResponseNew {
private String meta;
private String info;
private String respNew;
private String respbBest;
//...
}
The JSONs I need:
{
"meta": "",
"info": "",
"respOne": ""
}
And
{
"meta": "",
"info": "",
"respNew": "",
"respbBest": ""
}
So, I want to extract general info to one class and have something like this:
public class GeneralSubResponse {
private String meta;
private String info;
//..
}
public class MyResponse {
/*#JsonExpanded*/
private GeneralSubResponse generalInfo;
private String respOne;
//...
}
String types - just for examples, there can be any object of any nesting...
Is it possible using Jackson lib? Or is there exist any other way to do something like that? The main concern is to not duplicate code for each Object.

You can do it with common class inheritance or adding it as unwrapped object:
Option 1: with Java inheritance:
public class MyResponse extends GeneralSubResponse {
private String respOne;
//...
}
public class MyResponseNew extends GeneralSubResponse{
private String respNew;
private String respbBest;
}
Option 2: JsonUnwrapped object as object property:
public class MyResponseUnwrapped{
#JsonUnwrapped
private GeneralSubResponse subResponse;
private String respOne;
}
public class MyResponseNewUnwrapped{
#JsonUnwrapped
private GeneralSubResponse subResponse;
private String respNew;
private String respbBest;
}
Test (both options):
public class Test {
public static String getJsonString(Object o){
ObjectMapper mapper = new ObjectMapper();
//For testing
try {
//Convert object to JSON string
String jsonInString = mapper.writeValueAsString(o);
//System.out.println(jsonInString);
return jsonInString;
} catch (JsonProcessingException e){
e.printStackTrace();
}
return null;
}
public static void main(String args[]){
MyResponse myResponse = new MyResponse();
myResponse.setInfo("info");
myResponse.setMeta("meta");
myResponse.setRespOne("respOne");
System.out.println(myResponse.getClass().getSimpleName() + " = " + Test.getJsonString(myResponse ));
System.out.println("------------------------------");
MyResponseNew myResponseNew = new MyResponseNew();
myResponseNew.setInfo("infoNew");
myResponseNew.setMeta("metaNew");
myResponseNew.setRespbBest("respBest");
myResponseNew.setRespNew("respNew");
System.out.println(myResponseNew.getClass().getSimpleName() + " = " + Test.getJsonString(myResponseNew));
System.out.println("------------------------------");
MyResponseUnwrapped myResponseUnwrapped = new MyResponseUnwrapped();
GeneralSubResponse subResponse = new GeneralSubResponse();
subResponse.setInfo("infoUnwrapped");
subResponse.setMeta("metaUnwrapped");
myResponseUnwrapped.setSubResponse(subResponse );
myResponseUnwrapped.setRespOne("respTwo");
System.out.println(myResponseUnwrapped.getClass().getSimpleName() + " = " + Test.getJsonString(myResponseUnwrapped));
System.out.println("------------------------------");
MyResponseNewUnwrapped myResponseNewUnwrapped = new MyResponseNewUnwrapped();
GeneralSubResponse subResponse2 = new GeneralSubResponse();
subResponse2.setInfo("infoNewUnwrapped");
subResponse2.setMeta("metaNewUnwrapped");
myResponseNewUnwrapped.setSubResponse(subResponse2 );
myResponseNewUnwrapped.setRespbBest("respBestUnwrapped");
myResponseNewUnwrapped.setRespNew("respNewUnwrapped");
System.out.println(myResponseNewUnwrapped.getClass().getSimpleName() + " = " + Test.getJsonString(myResponseNewUnwrapped));
}
}
Result:
MyResponse = {"meta":"meta","info":"info","respOne":"respOne"}
------------------------------
MyResponseNew = {"meta":"metaNew","info":"infoNew","respNew":"respNew","respbBest":"respBest"}
------------------------------
MyResponseUnwrapped = {"meta":"metaUnwrapped","info":"infoUnwrapped","respOne":"respTwo"}
------------------------------
MyResponseNewUnwrapped = {"meta":"metaNewUnwrapped","info":"infoNewUnwrapped","respNew":"respNewUnwrapped","respbBest":"respBestUnwrapped"}

Related

Java - Extract array String from JSON and convert to JSON format

I have a JSON String as below:
"{ \"password\":\"des123\",\"ROU_DATA\":[{\"FORM_RECEIVING_TIME\":\"12:00:00\",\"REMARKS\":\"Redemption of Unit\"}, {\"FORM_RECEIVING_TIME\":\"13:00:00\",\"REMARKS\":\"sALE of Unit\"}] }";
Now I want to extract the Array from it and need to use it as a separate pojo class so that I can iterate over each value..
Now the problem is, when I try to convert the complete String to Map and get the Array value from the map.. It transforms its format to MAp format like:
{FORM_RECEIVING_DATE = 12:00:00, etc..}
However json string should be {"FORM_RECEIVING_DATE": "12:00:00", etc..}
due to the MAp format its now allowing me to parse it using my POJO Class..
Please help to convert it to my JSONFormat ...
**NOTE: Please note that I can only use Jackson **.
CLASS A
ObjectMapper mapper2 = new ObjectMapper();
Map<String, Object> map;
map = mapper2.readValue(json, new TypeReference<Map<String, Object>>(){});
System.out.println("map: " + map.get("ROU_DATA") );
String array = map.get("ROU_DATA").toString();
String json2 = new ObjectMapper().writeValueAsString(array.replace("[", "").replace("]", ""));
String json3 = new ObjectMapper().writeValueAsString(json2);
System.out.println("json2>>" + json2);
System.out.println("json2>>" + json3);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// 1. convert JSON array to Array objects
ROU[] pp1 = mapper.readValue("{" + array.replace("=", ":") + "}", ROU[].class);
for (ROU person : pp1) {
System.out.println(person.getRemarks());
}
CLASS B
import com.fasterxml.jackson.annotation.JsonProperty;
public class ROU {
#JsonProperty("FORM_RECEIVING_TIME")
private String formdate;
#JsonProperty("REMARKS")
private String remarks;
public String getFormdate() {
return formdate;
}
public void setFormdate(String formdate) {
this.formdate = formdate;
}
public String getRemarks() {
return remarks;
}
public void setRemarks(String remarks) {
this.remarks = remarks;
}
}
map.get("ROU_DATA") returns a List object, and the toString() method of List does not generate JSON text.
You don't need to convert back to a JSON text just to get the ROU[] created, just call convertValue(...).
String input = "{ \"password\":\"des123\",\"ROU_DATA\":[{\"FORM_RECEIVING_TIME\":\"12:00:00\",\"REMARKS\":\"Redemption of Unit\"}, {\"FORM_RECEIVING_TIME\":\"13:00:00\",\"REMARKS\":\"sALE of Unit\"}] }";
ObjectMapper mapper2 = new ObjectMapper();
Map<?, ?> json = mapper2.readValue(input, Map.class);
ROU[] pp1 = mapper2.convertValue(json.get("ROU_DATA"), ROU[].class);
for (ROU person : pp1)
System.out.println(person.getRemarks());
Output
Redemption of Unit
sALE of Unit
class A
public class ROU {
#JsonProperty("FORM_RECEIVING_TIME")
private String formdate;
#JsonProperty("REMARKS")
private String remarks;
public String getFormdate() {
return formdate;
}
public void setFormdate(String formdate) {
this.formdate = formdate;
}
public String getRemarks() {
return remarks;
}
public void setRemarks(String remarks) {
this.remarks = remarks;
}
}
class B
public class ObjOuter {
private String password;
#JsonProperty("ROU_DATA")
private List<ROU> rous;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<ROU> getRous() {
return rous;
}
public void setRous(List<ROU> rous) {
this.rous = rous;
}
}
json to Object
ObjectMapper mapper = new ObjectMapper();
try {
ObjOuter outer = mapper.readValue(str, ObjOuter.class);
for (ROU rou : outer.getRous()) {
System.out.println(rou.getFormdate());
System.out.println(rou.getRemarks());
}
} catch (IOException e) {
e.printStackTrace();
}

Cannot deserialize instance of `org.json.JSONObject`

I have a basic SpringBoot 2.1.5.RELEASE app. Using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file with some RestControllers.
In 1 of the controller this is the body I send:
{
"depositHotel": "xxx",
"destinationHotel": "aaa",
"depositHotelAmount": "0.2",
"destinationHotelAmount": "4",
"destinationAddress": [{
"address": "asdf",
"tag": ""
}],
"refundAddress": [{
"address": "pio",
"tag": ""
}]
}
so I create this class to use it as a RequestBody:
public class HotelswitchHotelOrderRequestBody {
public static class Builder {
private String depositHotel;
private String destinationHotel;
private Float depositHotelAmount;
private Float destinationHotelAmount;
private JSONObject destinationAddress;
private JSONObject refundAddress;
public Builder(String depositHotel, String destinationHotel) {
this.depositHotel = depositHotel;
this.destinationHotel = destinationHotel;
}
public Builder withDepositHotelAmount (Float depositHotelAmount) {
this.depositHotelAmount = depositHotelAmount;
return this;
}
public Builder withDestinationHotelAmount (Float destinationHotelAmount) {
this.destinationHotelAmount = destinationHotelAmount;
return this;
}
public Builder toDestinationAddress (JSONObject destinationAddress) {
this.destinationAddress = destinationAddress;
return this;
}
public Builder toRefundAddress (JSONObject refundAddress) {
this.refundAddress = refundAddress;
return this;
}
public HotelswitchHotelOrderRequestBody build(){
HotelswitchHotelOrderRequestBody order = new HotelswitchHotelOrderRequestBody();
order.depositHotel = this.depositHotel;
order.depositHotelAmount = this.depositHotelAmount;
order.destinationAddress = this.destinationAddress;
order.destinationHotel = this.destinationHotel;
order.destinationHotelAmount = this.destinationHotelAmount;
order.refundAddress = this.refundAddress;
return order;
}
}
private String depositHotel;
private String destinationHotel;
private Float depositHotelAmount;
private Float destinationHotelAmount;
private JSONObject destinationAddress;
private JSONObject refundAddress;
private HotelswitchHotelOrderRequestBody () {
//Constructor is now private.
}
public String getDepositHotel() {
return depositHotel;
}
public void setDepositHotel(String depositHotel) {
this.depositHotel = depositHotel;
}
public String getDestinationHotel() {
return destinationHotel;
}
public void setDestinationHotel(String destinationHotel) {
this.destinationHotel = destinationHotel;
}
public Float getDepositHotelAmount() {
return depositHotelAmount;
}
public void setDepositHotelAmount(Float depositHotelAmount) {
this.depositHotelAmount = depositHotelAmount;
}
public Float getDestinationHotelAmount() {
return destinationHotelAmount;
}
public void setDestinationHotelAmount(Float destinationHotelAmount) {
this.destinationHotelAmount = destinationHotelAmount;
}
public JSONObject getDestinationAddress() {
return destinationAddress;
}
public void setDestinationAddress(JSONObject destinationAddress) {
this.destinationAddress = destinationAddress;
}
public JSONObject getRefundAddress() {
return refundAddress;
}
public void setRefundAddress(JSONObject refundAddress) {
this.refundAddress = refundAddress;
}
}
But I have this error when receiving the object:
JSON parse error: out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `org.json.JSONObject` out of START_ARRAY token
JSONObject's representation in actual JSON is a hash i.e. {...}. In your json data you're providing an array of hashes [{...}] which is not the same. Judging from your domain I don't think it has to be multiple values, so you can just omit [] in your payload and if it does then the fields in your Java class can be defined as JSONArray.
However, I think you should go with defining an Address class and either using
private Address destinationAddress;
private Address refundAddress;
or if it indeed does have to be an object array
private List<Address> destinationAddresses;
private List<Address> refundAddresses;
I had a similar usecase , where I could not define the json to a POJO. Using com.fasterxml.jackson.databind.JsonNode instead of the JSONObject worked.

Java JSON Processing

I'm having a hard time processing the below JSON with Java, which is being returned from on an external Ansible playbook:
{"Sample":
{
"tag_description":"abc","tag_category_id":"def","tag_id":"ghi"
},
"Sample1":
{
"tag_description":"jkl","tag_category_id":"mno","tag_id":"pqr"
}
}
I've been able to successfully parse one section of the JSON using a custom deserializer, though it only ever gets the first section. Any ideas are hugely appreciated.
#JsonComponent
public class TagSerializer extends JsonDeserializer<Tag> {
#Override
public Tag deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException,
JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = mapper.getFactory();
JsonNode treeNode = jsonParser.getCodec().readTree(jsonParser);
Iterator<Map.Entry<String, JsonNode>> fields = treeNode.fields();
String name = "";
// collect the tag name
Map.Entry<String, JsonNode> entry = fields.next();
name = entry.getKey();
// now that we have the tag name, parse it as a separate JSON object
JsonNode node = entry.getValue();
// get the values from the JSON
String description = node.get("tag_description").asText();
String category_id = node.get("tag_category_id").asText();
String tag_id = node.get("tag_id").asText();
return new Tag(name, category_id, description, tag_id);
}
}
I'm calling the method from a Spring Boot REST API endpoint, and my 'tag' model is a Spring entity:
'Tag' model:
#Entity
#JsonDeserialize(using = TagSerializer.class)
public class Tag {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
private String tag_category_id;
private String tag_description;
private String tag_id;
//JPA requires that a default constructor exists
//for entities
protected Tag() {}
public Tag(String name,
String tag_category_id,
String tag_description,
String tag_id) {
this.name = name;
this.tag_category_id = tag_category_id;
this.tag_description = tag_description;
this.tag_id = tag_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTag_category_id() {
return tag_category_id;
}
public void setTag_category_id(String tag_category_id) {
this.tag_category_id = tag_category_id;
}
public String getTag_description() {
return tag_description;
}
public void setTag_description(String tag_description) {
this.tag_description = tag_description;
}
public String getTag_id() {
return tag_id;
}
public void setTag_id(String tag_id) {
this.tag_id = tag_id;
}
public String toString() {
return "<Tag:[Name: " + this.name + "],[tag_category: "+
this.tag_category_id + "],[tag_description: "+
this.tag_description + "],[tag_id:"+this.tag_id+"]";
}
}
Spring Boot endpoint:
#PostMapping(value="/store", consumes = APPLICATION_JSON_VALUE)
public void tagJson(#RequestBody String json) {
// delete any existing tags
tagRepository.deleteAll();
//lets modify the json to make it look nicer
String modjson = "["+json+"]";
ObjectMapper mapper = new ObjectMapper();
try {
Tag[] tags = mapper.readValue(modjson, Tag[].class);
for (Tag t : tags)
tagRepository.save(t);
} catch (Exception exception) {
exception.printStackTrace();
}
}
If you are using Spring MVC consider explicitly declare desired type when referreing to #RequestBody and let the framework do the job for you
#PostMapping(value="/store", consumes = APPLICATION_JSON_VALUE)
public void tagJson(#RequestBody Map<String, Tag> json) {
// Do not mess with ObjectMapper here, Spring will do the thing for you
}
This isn't a direct answer but a guide in a possible direction, using Gson.
package test;
import java.util.Map;
import com.google.gson.Gson;
public class JsonTest {
public static void main(final String... args) {
new JsonTest().run();
}
public void run() {
final Gson gson = new Gson();
final Map<?, ?> result = gson.fromJson("{" +
" \"Sample\": {" +
" \"tag_description\": \"abc\"," +
" \"tag_category_id\": \"def\"," +
" \"tag_id\": \"ghi\"" +
" }," +
" \"Sample1\": {" +
" \"tag_description\": \"jkl\"," +
" \"tag_category_id\": \"mno\"," +
" \"tag_id\": \"pqr\"" +
" }" +
"}", Map.class);
System.out.println("Map size: " + result.size());
}
}
The resulting size is 2. The map entries are keyed Sample, Sample1, and the values are lists containing the nodes. You can see this using a debugger.

Realm can't create Nested Objects from Json

I've been trying to create a nested RealmObject using a json but it only creates the first Object and not the nested ones. I would appreciate a help on this.
my Realm classes:
Content.java
public class Content extends RealmObject {
private String uuid;
RealmList<ContentDetailModel> ContentDetail;
public Content() {
super();
this.uuid = UUID.randomUUID().toString();
}
public String getUuid() {
return uuid;
}
public RealmList<ContentDetailModel> getContentDetails() {
return ContentDetail;
}
public void setContentDetails(RealmList<ContentDetailModel> contentDetails) {
this.ContentDetail = contentDetails;
}
}
ContentDetailModel.java:
public class ContentDetailModel extends RealmObject {
String FileName;
String ContentTypeID;
RealmList<ContentDetailMetadataModel> ContentDetailMetadata;
RealmResults<Content> content = null;
public String getFileName() {
return FileName;
}
public void setFileName(String fileName) {
FileName = fileName;
}
public String getContentTypeID() {
return ContentTypeID;
}
public void setContentTypeID(String contentTypeID) {
ContentTypeID = contentTypeID;
}
public RealmList<ContentDetailMetadataModel> getContentDetailMetadata() {
return ContentDetailMetadata;
}
public void setContentDetailMetadata(RealmList<ContentDetailMetadataModel> contentDetailMetadataz) {
this.ContentDetailMetadata = contentDetailMetadataz;
}
}
and the rest of nested classes are like these. my Json string is as follows:
"
{
"Content":{
"ContentDetail":[
{
"FileName":"test.mp3",
"ContentTypeID":3,
"ContentDetailMetadata":{
"Metadata":[
{
"ID":2,
"Value":"2017-08-02 09:40:30"
},
{
"ID":1,
"Value":"35.73876557934912,51.50785446166992"
}
]
}
},
{
"FileName":"2.jpg",
"ContentTypeID":2,
"ContentDetailMetadata":[
{
"Metadata":{
"ID":2,
"Value":"2017-08-02 09:40:30"
}
},
{
"Metadata":{
"ID":1,
"Value":"35.73876557934912,51.50785446166992"
}
}
]
}
]
}
}
"
and the code I use to do it is :
realm.createObjectFromJson(json)
{
"Content":{
"ContentDetail":[
{
"FileName":"test.mp3",
"ContentTypeID":3,
"ContentDetailMetadata":[{
"Metadata":[
{
"ID":2,
"Value":"2017-08-02 09:40:30"
},
{
"ID":1,
"Value":"35.73876557934912,51.50785446166992"
}
]
}]
},
Translates to:
public class Root extends RealmObject {
private Content Content;
}
public class Content extends RealmObject {
private RealmList<ContentDetail> ContentDetail;
#LinkingObjects("Content")
private final RealmResults<Root> roots = null;
}
public class ContentDetail extends RealmObject {
private String FileName;
private long ContentTypeID;
//private ContentDetailMetadata ContentDetailMetadata;
private RealmList<ContentDetailMetadata> ContentDetailMetadata;
#LinkingObjects("ContentDetail")
private final RealmResults<Content> contents = null;
}
public class ContentDetailMetadata extends RealmObject {
private RealmList<Metadata> Metadata;
#LinkingObjects("ContentDetailMetadata")
private final RealmResults<ContentDetail> contentDetails = null;
}
public class Metadata extends RealmObject {
private long ID;
private String Value;
#LinkingObjects("Metadata")
private final RealmResults<ContentDetailMetadata> contentDetailMetadatas = null;
}
If your schema doesn't look like that, then createOrUpdateFromJson() won't work.
Personally I would advise against using this schema though, it's pretty bad as a Realm schema. It's advisable to parse the JSON and then map it into a schema that makes more sense!
It looks like your JSON has put all fields for the Content object under the Context JSON object instead of directly under the top-level object where it should be.
If you do this, it should work:
realm.createObjectFromJson(Content.class, json.getJSONObject("Content"));

JSON parsing through GSON returns null values

I am trying to read the values of a JSON output.
This is the JSON output:
{"nameOfSummoner":{"id":56529189,"name":"test","profileIconId":550,"summonerLevel":30,"revisionDate":1422110739000}}
And with the following code I am trying to read it:
final Connector connector = new Connector();
String response = connector.connect("link"); // (Returns a String value of the JSON)
final Gson gson = new Gson();
final Summoner summoner = gson.fromJson(response, Summoner.class); //Summoner is a model class
System.out.println(summoner);
Summoner class:
public class Summoner {
private String name;
private long profileIconId;
private long summonerLevel;
private long revisionDate;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public long getProfileIconId() {
return profileIconId;
}
public void setProfileIconId(final long profileIconId) {
this.profileIconId = profileIconId;
}
public long getSummonerLevel() {
return summonerLevel;
}
public void setSummonerLevel(final long summonerLevel) {
this.summonerLevel = summonerLevel;
}
public long getRevisionDate() {
return revisionDate;
}
public void setRevisionDate
(long revisionDate) {
this.revisionDate = revisionDate;
}
#Override
public String toString() {
return "Summoner{" +
"name='" + name + '\'' +
", profileIconId=" + profileIconId +
", summonerLevel=" + summonerLevel +
", revisionDate=" + revisionDate +
'}';
}
}
And I get the following output on the console:
Summoner{name='null', profileIconId=0, summonerLevel=0, revisionDate=0}
I have sadly no idea why this happens. Any help I get is appreciated. I am fairly sure it has to do with the JSON output that "nameOfSummoner" is on top and maybe that's why it does not read what is below.
As mentioned by #PeterMmm , your input is a map with 1 key-value pair.
You need to Create another POJO with Summoner object as attribute:
public class Sample {
private Summoner nameOfSummoner;
//getters and setters
}
and then try parsing. Or, you could create a Map and parse.
Map<String, Summoner> responseObj = new HashMap<String, Summoner>();
responseObj= gson.fromJson(response, responseObj.class);
Summoner obj = responseObj.get("nameOfSummoner");
You will also need to have "id" attribute in Summoner class I believe, else gson will throw an exception.

Categories