Here is a java class CreateDoc which is sent from One web service that is producer side to another web service which is consumer side as List with content-type:Json
Below is the class representation
class CreateDoc{
DocMetData dMetaData;
DocContent dCont;
}
Class DocMetData {
String docNamel
String docType;
}
Class DocContent {
String data;
}
Once i receive the List as json in the consumer side i am not able to use this as a java Object and the content type is array with json nested inside an array.
Below is the Representation:
[
[
{
"dMetaData":{
"docName":"string",
"docType":"pdf"
},
"dCont":{
"data":"abc"
}
},
{
"dMetaData":{
"docName":"string",
"docType":"pdf"
},
"dCont":{
"data":"def"
}
},
{
"dMetaData":{
"docName":"string",
"docType":"pdf"
},
"dCont":{
"data":"ghk"
}
}
]
]
Question is how to process this and be able to use the data and represent as List.
Here's some sample code that shows how you can use the Jackson ObjectMapper to parse the data. Note that the code assumes the data is stored in a file, you can modify it as needed to suit your needs.
Here's the main class:
package parsing.arrayofarray;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ArrayOfArray {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
String data = null;
try {
data = new String(Files.readAllBytes(Paths.get("src/main/resources/jsonArrayOfArray.json")));
} catch (IOException e1) {
e1.printStackTrace();
}
List<List<CreateDoc>> results = null;
try {
results = mapper.readValue(data, new TypeReference<List<List<CreateDoc>>>(){});
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(results);
}
}
and here are the supporting classes, first CreateDoc:
package parsing.arrayofarray;
public class CreateDoc {
DocMetData dMetaData;
DocContent dCont;
public DocMetData getdMetaData() {
return dMetaData;
}
public void setdMetaData(DocMetData dMetaData) {
this.dMetaData = dMetaData;
}
public DocContent getdCont() {
return dCont;
}
public void setdCont(DocContent dCont) {
this.dCont = dCont;
}
#Override
public String toString() {
return "CreateDoc [dMetaData=" + dMetaData + ", dCont=" + dCont + "]";
}
}
and DocContent:
package parsing.arrayofarray;
public class DocContent {
#Override
public String toString() {
return "DocContent [data=" + data + "]";
}
String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
and the DocMetData:
package parsing.arrayofarray;
public class DocMetData {
String docName;
String docType;
public String getDocNamel() {
return docName;
}
public void setDocName(String docName) {
this.docName = docName;
}
#Override
public String toString() {
return "DocMetData [docNamel=" + docName + ", docType=" + docType + "]";
}
public String getDocType() {
return docType;
}
public void setDocType(String docType) {
this.docType = docType;
}
}
The output from the println is:
[[CreateDoc [dMetaData=DocMetData [docNamel=string, docType=pdf], dCont=DocContent [data=abc]], CreateDoc [dMetaData=DocMetData [docNamel=string, docType=pdf], dCont=DocContent [data=def]], CreateDoc [dMetaData=DocMetData [docNamel=string, docType=pdf], dCont=DocContent [data=ghk]]]]
You can use JSONArray(org.json) to parse the first list, and parse with GSON the inside list to create a List of CreatDoc. You can use only GSON to parse the first array too
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
public class Deserializer {
public static void main(String[] args) {
JSONArray jsonArray = new JSONArray(
"[[{\"dMetaData\": {\"docName\": \"string\",\"docType\": \"pdf\"},\"dCont\": {\"data\": \"abc\"}},{\"dMetaData\": {\"docName\": \"string\",\"docType\": \"pdf\"},\"dCont\": {\"data\": \"def\"}},{\"dMetaData\": {\"docName\": \"string\",\"docType\": \"pdf\"},\"dCont\": {\"data\": \"ghk\"}}]]");
JSONArray docsArray = jsonArray.getJSONArray(0);
List<CreateDoc> docsList = new Gson().fromJson(docsArray.toString(),
new TypeToken<ArrayList<CreateDoc>>() {}.getType());
docsList.forEach(System.out::println);
}
public static class CreateDoc {
DocMetData dMetaData;
DocContent dCont;
#Override
public String toString() {
return this.dMetaData.toString() + " " + this.dCont.toString();
}
}
public static class DocMetData {
String docName;
String docType;
#Override
public String toString() {
return "name: " + this.docName + " type: " + this.docType;
}
}
public static class DocContent {
String data;
#Override
public String toString() {
return "data: " + this.data;
}
}
}
You can use GSON to parse the message into a JSONArray with JSONObjects. Then create a parser for each class to convert the fields from the JSONObject into Java objects. Similar question is anwered here.
I think the problem is you are trying to map json to CreateDoc instead of CreateDoc List. If you are using spring boot to manage rest layer in your application use #Requestbody List CreateDoc in the method to convert your json. This will use Jackson converter internally. Otherwise you can use Jackson converter jar to convert your json to objects.
Related
I have JSON Array as below and want to sum values of JSON object and create new JSON object of sum inside a JSON array:
{
"client":[
{
"member":12,
"group":"g1"
},
{
"member":17,
"group":"g2"
}
],
"client2":[
{
"member":14,
"group":"g11"
},
{
"member":175,
"group":"g22"
}
]
}
I want to sum the member value for each jsonobject inside the jsonarray and create extra json and put it inside client array. The expected json should look like below:
{
"client":[
{
"member":12,
"group":"g1"
},
{
"member":17,
"group":"g2"
},
{
"totalMember":29,
"group":"all"
}
],
"client2":[
{
"member":14,
"group":"g11"
},
{
"member":175,
"group":"g22"
},
{
"totalMember":189,
"group":"all"
}
]
}
I tried as:
mainJson.fieldNames().forEach(fn->{
JsonArray jsonArray = mainJson.getJsonArray(fn);
int id = 0;
for (int i = 0; i < jsonArray.size(); i++) {
id += jsonArray.getJsonObject(i).getInteger("id");
JsonObject jsonObject = new JsonObject().put("id",id).put("group","all");
jsonArray.add(jsonObject);
mainJson.put(fn,jsonArray);
}
});
Your expected JSON string is not normal because any JSON objects belong to the same JSON array should have the same structure, so the output JSON string should look like as below:
{
"client":[
{
"member":12,
"group":"g1"
},
{
"member":17,
"group":"g2"
},
{
"member":29,
"group":"all"
}
],
...
}
If your expected JSON string can be revised so, then here comes another way to achieve what you want by following steps with Jackson and Lambda Expression (since Java 8):
Step 1
Create POJOs and use #JsonAnySetter to serialize client and client2 to List<ClientInfo>, and use #JsonIgnore for getName() for deserialization to ignore field name.
class RootPojo {
private List<ClientInfo> clients = new ArrayList<>();
#JsonAnySetter
public void setClients(String name, List<ClientInfo> client) {
client.forEach(e -> {
e.setName(name);
});
this.clients.addAll(client);
}
//general getter and toString
}
class ClientInfo {
private String name;
private int member;
private String group;
#JsonIgnore
public String getName() {
return name;
}
//general getters, setters and toString
}
Step 2
Serialize JSON string to pre-defined POJOs with Jackson:
ObjectMapper mapper = new ObjectMapper();
RootPojo rootPojo = mapper.readValue(inputJsonStr, RootPojo.class);
System.out.println(rootPojo.toString());
Console output:
RootPojo [clients=[ClientInfo [name=client, member=12, group=g1], ClientInfo [name=client, member=17, group=g2], ClientInfo [name=client2, member=14, group=g11], ClientInfo [name=client2, member=175, group=g22]]]
Step 3
Use Lambda Expression for grouping and summation which will also add the results as new JSON objects back to original JSON string.
rootPojo.getClients()
.stream()
.collect(Collectors.groupingBy(ClientInfo::getName,
Collectors.summingInt(ClientInfo::getMember)))
.forEach((k,v) -> {
ClientInfo clientInfo = new ClientInfo();
clientInfo.setName(k);
clientInfo.setGroup("all");
clientInfo.setMember(v);
rootPojo.getClients().add(clientInfo);
});
System.out.println(rootPojo.toString());
Console output:
RootPojo [clients=[ClientInfo [name=client, member=12, group=g1], ClientInfo [name=client, member=17, group=g2], ClientInfo [name=client2, member=14, group=g11], ClientInfo [name=client2, member=175, group=g22], ClientInfo [name=client, member=29, group=all], ClientInfo [name=client2, member=189, group=all]]]
Step 4
Transform rootPojo into Map<String, List<ClientInfo> then deserialize it to output JSON string:
Map<String, List<ClientInfo>> clientMap = new HashMap<>();
rootPojo.getClients().forEach(e -> {
if (clientMap.containsKey(e.getName())) {
clientMap.get(e.getName()).add(e);
} else {
List<ClientInfo> clients = new ArrayList<>();
clients.add(e);
clientMap.put(e.getName(), clients);
}
});
String outputJsonStr = mapper.writeValueAsString(clientMap);
System.out.println(outputJsonStr);
Console output:
{"client":[{"member":12,"group":"g1"},{"member":17,"group":"g2"},{"member":29,"group":"all"}],"client2":[{"member":14,"group":"g11"},{"member":175,"group":"g22"},{"member":189,"group":"all"}]}
So, below is a full worked example using gson library (googles json parser).
First i created the class for defining the initial json file:
import java.io.Serializable;
import java.util.ArrayList;
public class ClientSer implements Serializable {
ArrayList<ClientDataSer> client;
ArrayList<ClientDataSer> client2;
public ClientSer(ArrayList<ClientDataSer> client, ArrayList<ClientDataSer> client2) {
this.client = client;
this.client2 = client2;
}
public ArrayList<ClientDataSer> getClient() {
return client;
}
public void setClient(ArrayList<ClientDataSer> client) {
this.client = client;
}
public ArrayList<ClientDataSer> getClient2() {
return client2;
}
public void setClient2(ArrayList<ClientDataSer> client2) {
this.client2 = client2;
}
}
With client data ser looking like:
public class ClientDataSer extends ClientDataParentSer {
int member;
public ClientDataSer(int member, String group) {
super(group);
this.member = member;
}
public int getMember() {
return member;
}
public void setMember(int member) {
this.member = member;
}
}
In order for gson to uses files as definitions of data structure, they need to be serialisable. I will get the why ClientDataSer extends ClientDataParentSer in a moment.
The code for reading this file, caluclating the total member value and printing it to another file is shown below:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.*;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
try (Reader reader = new FileReader("test.json")) {
// Convert JSON File to Java Object
ClientSer clientSer = gson.fromJson(reader, ClientSer.class);
ClientNewSer clientNewSer = new ClientNewSer(getNewClientData(clientSer.getClient()), getNewClientData(clientSer.getClient2()));
try {
Writer writer = new FileWriter("testNew.json");
gson.toJson(clientNewSer, writer);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static ArrayList<ClientDataParentSer> getNewClientData(ArrayList<ClientDataSer> clientDataSerList) {
ArrayList<ClientDataParentSer> clientDataSers = new ArrayList<>();
int memberCounter = 0;
for (ClientDataParentSer clientDataSer : clientDataSerList) {
clientDataSers.add(clientDataSer);
memberCounter += ((ClientDataSer)clientDataSer).getMember();
}
ClientDataNewSer clientDataNewSer = new ClientDataNewSer("all", memberCounter);
clientDataSers.add(clientDataNewSer);
return clientDataSers;
}
}
So, as you wanted client and client2 to contain a list each with 2 different obejects (one with field member and group, and the other with fields total member and group), we had to do some hierarchy stuff.
If we make a parent class containing the common field (group):
import java.io.Serializable;
public class ClientDataParentSer implements Serializable {
private final String group;
public ClientDataParentSer(String group) {
this.group = group;
}
public String getGroup() {
return group;
}
}
and then make ClientDataSer and a new class:
public class ClientDataNewSer extends ClientDataParentSer {
int member;
public ClientDataNewSer(String group, int member) {
super(group);
this.member = member;
}
public int getMember() {
return member;
}
public void setMember(int member) {
this.member = member;
}
}
extend this parent class, we can have a list of ClientDataParentSer that contain both, ie the list the output json file needs.
the class for the new object is shown below:
import java.io.Serializable;
import java.util.ArrayList;
public class ClientNewSer implements Serializable {
ArrayList<ClientDataParentSer> client;
ArrayList<ClientDataParentSer> client2;
public ClientNewSer(ArrayList<ClientDataParentSer> client, ArrayList<ClientDataParentSer> client2) {
this.client = client;
this.client2 = client2;
}
public ArrayList<ClientDataParentSer> getClient() {
return client;
}
public void setClient(ArrayList<ClientDataParentSer> client) {
this.client = client;
}
public ArrayList<ClientDataParentSer> getClient2() {
return client2;
}
public void setClient2(ArrayList<ClientDataParentSer> client2) {
this.client2 = client2;
}
}
Any questions about anything comment below.
The full project is on my github here
[Unable to access property of another object stored in Arraylist]
I am creating an function to get JSON input in object from RESTful Web service input and format it again in JSON format to call other web service.
I have limitation that I can not use any JSON API for object mapping hence using Java reflection core API.
I am able to create JSON format from Input for simple elements but unable to access nested elements (another user defined POJO class ). I am using arraylist.
Input
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": [
{
"itemType": "NODE-ID",
"ItemName": "22BT_ORNC03"
},
{
"ItemType": "CCT",
"ItemName": "A_circuit_id"
}]
}
}
GenesisIncidents.class
import java.util.ArrayList;
import java.util.Date;
public class GenesisIncidents {
private String service;
private String affectedCI;
private ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems;
public GenesisIncidents(){}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getAffectedCI() {
return affectedCI;
}
public void setAffectedCI(String affectedCI) {
this.affectedCI = affectedCI;
}
public ArrayList<AdditionalAffectedItems> getOpt_additionalAffectedItems() {
return opt_additionalAffectedItems;
}
public void setOpt_additionalAffectedItems(ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems) {
this.opt_additionalAffectedItems = opt_additionalAffectedItems;
}
}
AdditionalAffectedItems.class
public class AdditionalAffectedItems {
private String itemType;
private String itemName;
public AdditionalAffectedItems(){
super();
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
Implemetation
public void updateTicketExt(GenesisIncidents genesisIncidents) {
try{
Field allFields[]=genesisIncidents.getClass().getDeclaredFields();
Method allMethods[] = genesisIncidents.getClass().getDeclaredMethods();
String jsonString ="{\r\n \""+genesisIncidents.getClass().getName().toString().substring(48)+"\": {";
final String preStr="\r\n \""; //To create a JSON object format.
final String postStr="\": "; //To create a JSON object format.
int totalNoOfFields=allFields.length;
for (Field field : allFields) {
System.out.println(field.getType());
String getter="get"+StringUtils.capitalize(field.getName());
Method method= genesisIncidents.getClass().getMethod(getter, null);
try{
if(field.getType().toString().contains("Integer"))
jsonString=jsonString + preStr + field.getName() + postStr +method.invoke(genesisIncidents).toString()+",";
else
jsonString=jsonString + preStr + field.getName() + postStr +"\""+method.invoke(genesisIncidents).toString()+"\",";
if(field.getType().toString().contains("ArrayList")){
System.out.println("ArrayListElement found");
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
//convertArrayToJSON(field, genesisIncidents);
}
}catch(NullPointerException npe)
{
System.out.println("Null value in field.");
continue;
}
}
jsonString=jsonString.substring(0,jsonString.length()-1);
jsonString=jsonString+"\r\n }\r\n }";
System.out.println("\n"+jsonString);
}catch(Exception jex){
jex.printStackTrace();
}
}
My below code line is unable to access object stored under array list.
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
OUTPUT
karaf#root>class java.lang.String
class java.lang.String
class java.lang.String
class java.util.ArrayList
ArrayListElement found
null
null
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": " [org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#5881a 895, org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#399b4e eb]"
}
}
I have fiddled around with your example I have managed to get it working. This will produce the correct JSON string by passing in an instance of a GenesisIncident object. I guess that there is much room for improvement here but this can serve as an example.
public static String genesisToJson(GenesisIncidents incidents) {
try{
StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.append("{\r\n \"")
.append(incidents.getClass().getSimpleName())
.append("\": {");
Field allFields[] = incidents.getClass().getDeclaredFields();
for (Field field : allFields) {
String getter = getGetterMethod(field);
Method method = incidents.getClass().getMethod(getter, null);
try{
if(field.getType().isAssignableFrom(Integer.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr)
.append(method.invoke(incidents).toString()).append(",");
} else if (field.getType().isAssignableFrom(String.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr).append("\"")
.append(method.invoke(incidents).toString()).append("\",");
} else if (field.getType().isAssignableFrom(List.class)) {
System.out.println("ArrayListElement found");
getInnerObjectToJson(field, incidents.getOptItems(), jsonBuilder);
}
} catch(NullPointerException npe) {
System.out.println("Null value in field.");
continue;
}
}
jsonBuilder.append("\r\n } \r\n }");
return jsonBuilder.toString();
}catch(Exception jex){
jex.printStackTrace();
}
return null;
}
private static void getInnerObjectToJson(Field field, List<AdditionalAffectedItems> items, StringBuilder builder)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
builder.append(preStr).append(field.getName()).append(postStr).append("[");
for (var item : items) {
var fields = List.of(item.getClass().getDeclaredFields());
builder.append("{");
for (var f : fields) {
String getter = getGetterMethod(f);
Method method = item.getClass().getMethod(getter, null);
builder.append(preStr).append(f.getName()).append(postStr).append("\"")
.append(method.invoke(item).toString()).append("\"");
if (!(fields.indexOf(f) == (fields.size() - 1))) {
builder.append(",");
}
}
if (items.indexOf(item) == (items.size() - 1)) {
builder.append("}\r\n");
} else {
builder.append("},\r\n");
}
}
builder.append("]");
}
private static String getGetterMethod(Field field) {
return "get" + StringUtils.capitalize(field.getName());
}
I need to map JSON obj to a class and its arrays to ArrayList in Android and it should have all the children data as well. (with nested arraylists too) and i need to convert updated data list again to jsonobject
my json string is
{
"type": "already_planted",
"crops": [
{
"crop_id": 1,
"crop_name": "apple",
"crop_details": [
{
"created_id": "2017-01-17",
"questions": [
{
"plants": "10"
},
{
"planted_by": "A person"
}
]
},
{
"created_id": "2017-01-30",
"questions": [
{
"plants": "15"
},
{
"planted_by": "B person"
}
]
}
]
},
{
"crop_id": 2,
"crop_name": "Cashew",
"crop_details": [
{
"created_id": "2017-01-17",
"questions": [
{
"plants": "11"
},
{
"planted_by": "c person"
}
]
}
]
}
]
}
First of all, you need to create the class that you are going to map JSON inside.
Fortunately, there is a website that can do it for you here
secondly, you can use google Gson library for easy mapping
1. add the dependency.
dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
}
2. from your object to JSON.
MyData data =new MyData() ; //initialize the constructor
Gson gson = new Gson();
String Json = gson.toJson(data ); //see firstly above above
//now you have the json string do whatever.
3. from JSON to object .
String jsonString =doSthToGetJson(); //http request
MyData data =new MyData() ;
Gson gson = new Gson();
data= gson.fromJson(jsonString,MyData.class);
//now you have Pojo do whatever
for more information about gson see this tutorial.
If you use JsonObject, you can define your entity class as this:
public class Entity {
String type;
List<Crops> crops;
}
public class Crops {
long crop_id;
String crop_name;
List<CropDetail> crop_details;
}
public class CropDetail {
String created_id;
List<Question> questions;
}
public class Question {
int plants;
String planted_by;
}
public void convert(String json){
JsonObject jsonObject = new JsonObject(jsonstring);
Entity entity = new Entity();
entity.type = jsonObject.optString("type");
entity.crops = new ArrayList<>();
JsonArray arr = jsonObject.optJSONArray("crops");
for (int i = 0; i < arr.length(); i++) {
JSONObject crops = arr.optJSONObject(i);
Crops cps = new Crops();
cps.crop_id = crops.optLong("crop_id");
cps.crop_name = crops.optString("crop_name");
cps.crop_details = new ArrayList<>();
JsonArray details = crops.optJsonArray("crop_details");
// some other serialize codes
..........
}
}
So you can nested to convert your json string to an entity class.
Here is how I do it without any packages, this do the work for me for small use cases:
My modal class:
package prog.com.quizapp.models;
import org.json.JSONException;
import org.json.JSONObject;
public class Question {
private String question;
private String correct_answer;
private String answer_a;
private String answer_b;
private String answer_c;
private String answer_d;
public Question() {
}
public Question(String question, String answer_a, String answer_b, String answer_c, String answer_d, String correct_answer) {
this.question = question;
this.answer_a = answer_a;
this.answer_b = answer_b;
this.answer_c = answer_c;
this.answer_d = answer_d;
this.correct_answer = correct_answer;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getCorrect_answer() {
return correct_answer;
}
public void setCorrect_answer(String correct_answer) {
this.correct_answer = correct_answer;
}
public String getAnswer_a() {
return answer_a;
}
public void setAnswer_a(String answer_a) {
this.answer_a = answer_a;
}
public String getAnswer_b() {
return answer_b;
}
public void setAnswer_b(String answer_b) {
this.answer_b = answer_b;
}
public String getAnswer_c() {
return answer_c;
}
public void setAnswer_c(String answer_c) {
this.answer_c = answer_c;
}
public String getAnswer_d() {
return answer_d;
}
public void setAnswer_d(String answer_d) {
this.answer_d = answer_d;
}
#Override
public String toString() {
return "Question{" +
"question='" + question + '\'' +
", correct_answer='" + correct_answer + '\'' +
", answer_a='" + answer_a + '\'' +
", answer_b='" + answer_b + '\'' +
", answer_c='" + answer_c + '\'' +
", answer_d='" + answer_d + '\'' +
'}';
}
public static Question fromJson(JSONObject obj) throws JSONException {
return new Question(
obj.getString("question"),
obj.getString("answer_a"),
obj.getString("answer_b"),
obj.getString("answer_c"),
obj.getString("answer_d"),
obj.getString("correct_answer"));
}
}
And I have another class to get the json file from assets directory and mapped JsonObject to my model class Question:
package prog.com.quizapp.utils;
import android.content.Context;
import android.util.Log;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import prog.com.quizapp.models.Question;
public class JsonSqlQueryMapper {
private Context mContext;
public JsonSqlQueryMapper(Context context) {
this.mContext = context;
}
private static final String TAG = "JsonSqlQueryMapper";
public JSONObject loadJSONFromAsset() {
String json = null;
try {
InputStream is = mContext.getAssets().open("quiz_app.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
try {
JSONObject quizObject = new JSONObject(json).getJSONObject("quiz");
return quizObject;
} catch (Exception e) {
Log.d(TAG, "loadJSONFromAsset: " + e.getMessage());
return null;
}
}
public ArrayList<Question> generateInsertQueryForJsonObjects() {
ArrayList<Question> questions = new ArrayList<>();
JSONObject jsonObject = loadJSONFromAsset();
try {
Iterator<String> iter = jsonObject.keys();
while (iter.hasNext()) {
String key = iter.next();
JSONObject value = jsonObject.getJSONObject(key);
Question question = Question.fromJson(value.getJSONObject("question_two"));
questions.add(question);
Log.d(TAG, "generateInsertQueryForJsonObjects: " + question.getAnswer_a());
}
} catch (Exception e) {
e.printStackTrace();
}
return questions;
}
}
And in my MainActivity -> onCreate:
JsonSqlQueryMapper mapper = new JsonSqlQueryMapper(MainActivity.this);
mapper.generateInsertQueryForJsonObjects();
To check that everything working as I want. Here is the json file if you want to check https://github.com/Blasanka/android_quiz_app/blob/sqlite_db_app/app/src/main/assets/quiz_app.json
Regards!
I have a simple wrapper class.
class Wrapper {
int id;
Object command;
}
command could be an object that I get from the outside, and I cannot create an interface to hold the possible types together.
I'd like to serialize it simply:
String json = objectMapper.writeValueAsString(wrapper);
So that I get:
{"id":"1","command":{"type" : "objectType", "key0": "val0", ... other properties...}}
Ideally I'd build a registry with the possible values of type and the corresponding class names as values, so I could deserialize it like this:
Wrapper wrapper = objectMapper.readValue(bytes, Wrapper.class);
(objectMapper is com.fasterxml.jackson.databind.ObjectMapper)
Is there a way to achieve this with Jackson?
You can use the Jackson polymorphic type handling. You can declare which type the command property can be using #JsonTypeXXX annotations.
Here is a complete example:
public class JacksonTypeInfoOnObject {
public static class Bean {
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(Command1.class),
#JsonSubTypes.Type(Command2.class)
})
public final Object command;
#JsonCreator
public Bean(#JsonProperty("command") final Object command) {this.command = command;}
#Override
public String toString() {
return "Bean{" +
"command=" + command +
'}';
}
}
#JsonTypeName("cmd1")
public static class Command1 {
#Override
public String toString() {
return "Command1{}";
}
}
#JsonTypeName("cmd2")
public static class Command2 {
#Override
public String toString() {
return "Command2{}";
}
}
public static void main(String[] args) throws IOException {
final ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
final List<Bean> list = Arrays.asList(
new Bean(new Command1()),
new Bean(new Command2()));
final String json = mapper.writeValueAsString(list);
System.out.println(json);
final List<Bean> values = mapper.readValue(json, new TypeReference<List<Bean>>() {});
System.out.println(values);
}
}
Output:
[{"command":{"type":"cmd1"}},{"command":{"type":"cmd2"}}]
[Bean{command=Command1{}}, Bean{command=Command2{}}]
I changed the type of your command property to a Map<String, Object> and the Wrapper object can be serialized/deserialized as expected.
Below, is the output generated by the Main class:
SERIALIZE: {"id":1,"command":{"key0":"val0","type":"objectType"}}
DESERIALIZE: Wrapper [id=1, command={key0=val0, type=objectType}]
Main.java
package json;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
static ObjectMapper objectMapper = new ObjectMapper();
private static Wrapper createWrapper() {
Wrapper wrapper = new Wrapper();
Map<String, Object> command = new HashMap<String, Object>();
command.put("type", "objectType");
command.put("key0", "val0");
wrapper.id = 1;
wrapper.command = command;
return wrapper;
}
private static String serializeWrapper(Wrapper wrapperObj) {
try {
return objectMapper.writeValueAsString(wrapperObj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
private static Wrapper deserializeWrapper(String wrapperJsonStr) {
try {
return objectMapper.readValue(wrapperJsonStr, Wrapper.class);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
Wrapper wrapper = createWrapper();
String wrapperJsonStr = serializeWrapper(wrapper);
System.out.printf("SERIALIZE: %s%n", wrapperJsonStr);
Wrapper wrapperObj = deserializeWrapper(wrapperJsonStr);
System.out.printf("DESERIALIZE: %s%n", wrapperObj);
}
}
Wrapper.java
package json;
import java.util.Map;
public class Wrapper {
public int id;
public Map<String, Object> command;
#Override
public String toString() {
return "Wrapper [id=" + id + ", command=" + command + "]";
}
}
I study xstream these days.
But I found the xstream json tutorial which in its homepage is very simple.
I have an array as follows:
{
"mails":[
{
"uid":"ZC2027-mXOmcAtkfiztS0sEeJlkU25",
"relatedCardNums":"8299,0000,1531|8299,0000,1531",
"houseHolder":"",
"subject":"no-subject",
"receiveTime":"2012-05-27 00:00:00",
"bankName":"上海银行",
"cards":[]
}
],
"dealedNum":330,
"nextRequestDelay":"1",
"percent":"0",
"filterNum":410,
"resCode":"01",
"dealedBillNum":43,
"resMsg":"正在解析"
}
I want to convert this json string to a GetMailsDataResponseDto, but I dont know how to do?
Could you help me out?
package com.fund.etrading.ebankapp.base.credit.cardniu.ecardniu.dto;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.fund.etrading.ebankapp.base.credit.utils.FileUtils;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
public class GetMailsDataResponseDto extends ResponseBaseDto{
protected int dealedNum;
protected String nextRequestDelay;
protected String percent;
protected int filterNum;
protected int dealedBillNum;
protected List mails = new ArrayList();
public List getMails() {
return mails;
}
public int getDealedNum() {
return dealedNum;
}
public String getNextRequestDelay() {
return nextRequestDelay;
}
public String getPercent() {
return percent;
}
public int getFilterNum() {
return filterNum;
}
public int getDealedBillNum() {
return dealedBillNum;
}
public void fromJson(String json){
try {
json = FileUtils.get_content("C:\\Documents and Settings\\Administrator\\workspace\\99fund_java\\src\\com\\fund\\etrading\\ebankapp\\base\\credit\\新建 文本文档 (2).txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
json = "{\"root\":" + json + "}";
XStream xstream = new XStream(new JettisonMappedXmlDriver());
xstream.alias("root", this.getClass());
//xstream.addImplicitCollection(this.getClass(), "mails");
xstream.alias("mail", MailDto.class);
//xstream.aliasField("cards", MailDto.class, "cards");
//xstream.aliasField("currencyData", CardDto.class, "currencyData");
//xstream.aliasField("data", CurrencyDataDto.class, "data");
xstream.fromXML(json, this);
}
}
package com.fund.etrading.ebankapp.base.credit.cardniu.ecardniu.dto;
import java.util.ArrayList;
import java.util.List;
import com.fund.etrading.ebankapp.base.credit.BaseDto;
public class MailDto extends BaseDto{
protected String uid;
protected String relatedCardNums;
protected String houseHolder;
protected String subject;
protected String receiveTime;
protected String bankName;
protected List cards = new ArrayList();
public String getUid() {
return uid;
}
public String getRelatedCardNums() {
return relatedCardNums;
}
public String getHouseHolder() {
return houseHolder;
}
public String getSubject() {
return subject;
}
public String getReceiveTime() {
return receiveTime;
}
public String getBankName() {
return bankName;
}
public List getCards() {
return cards;
}
}
thanks in advance!
If you want to convert json string to your custom class(ex.GetMailsDataResponseDto), I recommend Google Gson.
If you use Gson, yon don't need fromJosn() method in GetMailsDataResponseDto class.
If you only use json parsing and have experiences of java script, I recommend Djson parser(java library).
"Djson Parse version 0.8a" -- http://blog.indf.net/category/Apps/djson
j1.txt - tip: "none BOM & UTF-8"
....
public void fromJson(String json){
//(real-code)--start
//Var var = Djson.parse(json);
//(real-code)--end
//--test-code--start
Var var = null;
try {
var = Djson.parse(new File("d:\\j1.txt"));
} catch (IOException e) {
e.printStackTrace();
}
//--test-code--end
this.dealedNum = var.get("dealedNum").toInt();
this.nextRequestDelay = var.get("nextRequestDelay").toString();
this.percent = var.get("percent").toString();
this.filterNum = var.get("filterNum").toInt();
this.dealedBillNum = var.get("dealedBillNum").toInt();
for(int i=0; i<var.get("mails").size(); i++) {
this.mails.add(var.get("mails").get(i).toObject()); // MAP type setting...
}
}