I have an ArrayList of custom Objects. Each of these objects have an arraylist of another custom object. Then these second level of custom objects have an arraylist of another custom object.
This is how the class hierarchy looks like
public class Undle {
private String undleStatus;
private ArrayList<ArcelFolder> arcelFolders;
public ArrayList<ArcelFolder> getArcelFolders() {
return arcelFolders;
}
public void setArcelFolders(ArrayList<ArcelFolder> arcelFolders) {
this.arcelFolders = arcelFolders;
}
//Other getter and setters
}
public class ArcelFolder {
private ArrayList<ArcelDocument> arcelDocuments;
private String arcelStatus;
public String getArcelStatus() {
return arcelStatus;
}
public void setArcelStatus(String arcelStatus) {
this.arcelStatus = arcelStatus;
}
public ArrayList<ArcelDocument> getArcelDocuments() {
return arcelDocuments;
}
public void setArcelDocuments(ArrayList<ArcelDocument> arcelDocuments) {
this.arcelDocuments = arcelDocuments;
}
}
public class ArcelDocument {
private String gain;
public String getGain() {
return gain;
}
public void setGain(String gain) {
this.gain = gain;
}
}
I have an arraylist of Undle objects
ArrayList<Undle> undleList = new ArrayList<Undle>();
// Create objects of ArcelFolder and ArcelDocument
// Add ArcelDocument list to ArcelFolder
// Add ArcelFolder list to Undle arraylist
I would like to convert Undle ArrayList to a JSON. How can I flatten this hierarcical structure of beans and put it in a JSON?
I tried doing something like
org.json.simple.JSONObject resultObj = new JSONObject(undleList);
and
org.json.simple.JSONArray arr = new JSONArray(undleList);
But it seems that they work only if a String ArrayList is passed.
Gson gson = new Gson();
Type type = new TypeToken<List<Bundle>>() {}.getType();
String json = gson.toJson(bundleList, type);
System.out.println(json);
List<Bundle> fromJson = gson.fromJson(json, type);
for (Bundle bundle : fromJson) {
System.out.println(bundle);
}
Related
I'm having a null return using Gson.fromJson() and I don't understand why.
I'm calling an API that returns some data with this format:
{
"RealisedItems":{
"realisedItem":[
{
"actionItem1":1,
"actionItem2":"ITEM_ANSWER",
"actionItem3":"CREATE_ITEM",
"actionItem4":[
"XXXXXXX"
]
},
{
"actionItem1":2,
"actionItem2":"ITEM_ANSWER",
"actionItem3":"LINK_ITEM",
"actionItem5":"202007050000",
"actionItem4":[
"XXXXXXX"
]
}
]
}
}
Here's my objects to receive the data :
public class RealisedItems {
private List<RealisedItem> realisedItem = null;
public List<RealisedItem> getRealisedItem() {
return realisedItem;
}
public void setRealisedItem(List<RealisedItem> realisedItem) {
this.realisedItem = realisedItem;
}
}
And
public class RealisedItem {
private Long actionItem1;
private String actionItem2;
private String actionItem3;
private List<String> actionItem4 = null;
private String actionItem5;
public Long getActionItem1() {
return actionItem1;
}
public void setActionItem1(Long actionItem1) {
this.actionItem1 = actionItem1;
}
public String getActionItem2() {
return actionItem2;
}
public void setActionItem2(String actionItem2) {
this.actionItem2 = actionItem2;
}
public String getActionItem3() {
return actionItem3;
}
public void setActionItem3(String actionItem3) {
this.actionItem3 = actionItem3;
}
public List<String> getActionItem4() {
return actionItem4;
}
public void setActionItem4(List<String> actionItem4) {
this.actionItem4 = actionItem4;
}
public String getActionItem5() {
return actionItem5;
}
public void setActionItem5(String actionItem5) {
this.actionItem5 = actionItem5;
}
}
Using the debug mode, I can see by that the response object from this line : gson.fromJson(response, RealisedItems.class); contains the Json in String format that you can see above but my list is null after this. I'm using the same code for another response from a different service and I have my object filled with data.
From what I can see, in the fist "realisedItem" object, I have 4 items while in the second, I have 5. Can this cause this issue?
I tried to change the list to an array (RealisedItem[]) but it's not working either.
I also tried to use the #Expose with #SerializedName and changing Gson gson = new Gson(); to Gson gson = new GsonBuilder().create(); and Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); with the fifth item not having the #Expose annotation, but I'm still having my list null.
Can you please enlight me? Thanks!
Thanks to #Andreas, I realized I've made a mistake and used RealisedItems as root object. I just created a new object called ItemsOutput which contains RealisedItems field. I added a #SerializedName annotation to indicate it's called "RealisedItems" with an uppercase and changed my Gson.fromJson() call with the newly created object. It's working.
Thanks!
I am trying to build a custom App to control Smart Home devices utilizing the Tasmota firmware and MQTT. Primarily that is smart lights at the moment. Therefore I have a Device class with children depending on the type of the device. Each device stores a DeviceState which is updated due to any changes made through the app. So the DeviceState is always the current state of the device. Depending on the device I need different DeviceStates, so again there is one superclass and subclass.
Now i want to store scenes with an ArrayList of DeviceStates to first store and than recreate certain light atmospheres. Therefore there is a class called Scene holding basic information and the described ArrayList.
To Store those lists i am using the Gson library in Android. My question is now how to be able to save those scenes objects with a polymorphic list inside.
I have followed this stackoverflow post: Gson serialize a list of polymorphic objects to save my devices as an Json String using the Gson library and a custom serializer / deserializer. But now Hence DeviceState doesn´t extend Scene I can´t use one serializer to create a String out of the Scene object. And if i would extend DeviceState to Scene, the DeviceState class would declare multiple JSON fields with the same name, because I am using "typeName" to differentiate those classes.
So basically i am getting the errors, that DeviceState doesn´t extend Scene or that DeviceState declares multiple JSON fields named "typeName".
public class Scene{
private ArrayList<DeviceState> states;
private String name;
private String room;
private String typeName;
public ArrayList<Scene> sceneList = new ArrayList<>();
public Scene(){
}
public Scene(String pName, String pRoom) {
name = pName;
room = pRoom;
states = new ArrayList<>();
typeName = "Scene";
}
public String getName() {
return name;
}
public String getRoom() {
return room;
}
public void addDevice(Device d) {
states.add(d.getState());
}
public void execute() {
System.out.println(states.size());
}
public String getTypeName(){
return typeName;
}
}
public class DeviceState {
private String typeName;
private String deviceTopic;
public static final String RGBWLightState = "RGBWLightState";
public static final String Default = "DeviceState";
public DeviceState(String pTypeName, String pDeviceTopic){
typeName = pTypeName;
deviceTopic = pDeviceTopic;
}
public DeviceState(){
typeName = Default;
}
public String getTypeName() {
return typeName;
}
}
public class CustomSceneSerializer implements JsonSerializer<ArrayList<Scene>> {
private static Map<String, Class> map = new TreeMap<>();
static {
map.put(DeviceState.RGBWLightState, RGBWLightState.class);
map.put(DeviceState.Default, DeviceState.class);
map.put("Scene", Scene.class);
}
#Override
public JsonElement serialize(ArrayList<Scene> src, Type typeOfSrc, JsonSerializationContext context) {
if(src == null) {
return null;
}else{
JsonArray ja = new JsonArray();
for(Scene s : src){
Class c = map.get(s.getTypeName());
if(c == null){
throw new RuntimeException("Unkown class: " + s.getTypeName());
}
ja.add(context.serialize(s, c));
}
return ja;
}
}
}
public class CustomSceneDeserializer implements JsonDeserializer<List<Scene>> {
private static Map<String, Class> map = new TreeMap<>();
static {
map.put(DeviceState.RGBWLightState, RGBWLightState.class);
map.put(DeviceState.Default, DeviceState.class);
map.put("Scene", Scene.class);
}
#Override
public List<Scene> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
ArrayList list = new ArrayList<Scene>();
JsonArray ja = json.getAsJsonArray();
for (JsonElement je : ja) {
String type = je.getAsJsonObject().get("typeName").getAsString();
Class c = map.get(type);
if (c == null)
throw new RuntimeException("Unknow class: " + type);
list.add(context.deserialize(je, c));
}
return list;
}
}
To save the Object holding a list of those objects I am using:
String json = preferences.getString("scene_holder", "");
GsonBuilder gb = new GsonBuilder();
List<Scene> al = new ArrayList<>();
gb.registerTypeAdapter(al.getClass(), new CustomSceneDeserializer());
gb.registerTypeAdapter(al.getClass(), new CustomSceneSerializer());
Gson gson = gb.create();
System.out.println(list.size());
list.get(0).execute();
System.out.println(json);
if (!(json.equals(""))) {
Scene result = gson.fromJson(json, Scene.class);
System.out.println(result.sceneList.size());
result.sceneList = list;
System.out.println(result.sceneList.size());
editor.putString("scene_holder", gson.toJson(result)).commit();
} else {
Scene scene = new Scene();
scene.sceneList = list;
editor.putString("scene_holder", gson.toJson(scene)).commit();
}
To the best of my understanding, Jackson will
serialize a public instance variable to the variable name
public List<String> myStrings = new ArrayList<>();
serializes to
{ 'myStrings' : [ ... ] }
serialize a private instance variable to the variable name if it has a public getter named getVariable():
private List<String> myStrings = new ArrayList<>();
public List<String> getMyStrings() { return myStrings; }
serializes similar to
{ 'myStrings' : [ ... ] }
However, what I am trying to achieve is to serialize it to a String (instead of array of Strings) based on another method, but keep the JSON key (based on #JsonInclude(JsonInclude.Include.NON_NULL) suppressing the original accessor in some cases
#JsonInclude(JsonInclude.Include.NON_NULL)
private boolean firstStringOnly = true;
private List<String> myStrings = new ArrayList<>();
public List<String> getMyStrings() { return firstStringOnly ? null: myStrings; }
public String getFirstString() { return firstStringOnly ? myStrings.get(0) : null; }
Desired JSON serialization:
For firstStringOnly==true: { 'myStrings' : 'first_String' } (using getFirstString())
For firstStringOnly==false: { 'myStrings' : [ ... ] } (using getMyStrings())
Is this possible to do? I'm specifically looking to avoid using custom serializers, and do this via annotations only.
You can assume a reasonably recent version of Jackson and Java 8.
Just to re-iterate, the question constraints are:
* NO custom serializer
* Both use cases produce the same JSON key
You can generalize getMyStrings() method and make it return Object. And inside check the flag and return first value or all values. Here is my sample
public class tst {
private static class YourObject {
private boolean firstStringOnly;
private List<String> myStrings = new ArrayList<>();
public YourObject(boolean firstStringOnly) {
this.firstStringOnly = firstStringOnly;
this.myStrings.add("str1");
this.myStrings.add("str2");
}
public Object getMyStrings(){
return firstStringOnly ? myStrings.get(0) : myStrings;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new YourObject(true)));
System.out.println(mapper.writeValueAsString(new YourObject(false)));
}
}
The output is
{"myStrings":"str1"}
{"myStrings":["str1","str2"]}
EDIT: Sorry, i have misread your initial question. I assume you want to keep both of the typed getters. Would this work for you?
public class TestClass {
private boolean firstStringOnly = true;
private List<String> myStrings = new ArrayList<>();
#JsonIgnore
public boolean isFirstStringOnly() {
return firstStringOnly;
}
public void setFirstStringOnly(boolean firstStringOnly) {
this.firstStringOnly = firstStringOnly;
}
#JsonIgnore
public List<String> getMyStrings() {
return firstStringOnly ? null : myStrings;
}
#JsonIgnore
public String getFirstString() { return firstStringOnly ? myStrings.get(0) : null; }
#JsonProperty("myStrings")
public Object getMyStringsForSerialization() {
return firstStringOnly ? getFirstString() : getMyStrings();
}
public void setMyStrings(List<String> myStrings) {
this.myStrings = myStrings;
}
Hi in my app i am using to create a JSON string. So i thought of using GSON. I have two function one is to store the arraylist and another is normal object. My problem is the ArrayList part is working fine but when i print the normal object function the arraylist object is added to the json part here is my coding
main class
JsonStructure json = new JsonStructure();
json.messages.add("msg 1");
json.messages.add("msg 2");
json.messages.add("msg 3");
json.asecs.add("asec 1");
json.asecs.add("asec 2");
json.asecs.add("asec 3");
Gson gson = new Gson();
output = gson.toJson(json);
Log.i("gson", output);
List<JsonStructure> Allergylist = new ArrayList<JsonStructure>();
for (int i = 0; i < 5; i++) {
JsonStructure oAllergy_Data = new JsonStructure();
oAllergy_Data.setIdmember("hi");
oAllergy_Data.setIduser("hello");
// Adding register to list
Allergylist.add(oAllergy_Data);
}
Gson newgson = new Gson();
String newoutput = newgson.toJson(Allergylist);
Log.i("gson new", newoutput);
and here is my object class
public class JsonStructure {
String idpeople;
String iduser;
String idmember;
ArrayList<String> messages = new ArrayList<String>();
ArrayList<String> asecs = new ArrayList<String>();
public JsonStructure() {
}
public String getIdpeople() {
return idpeople;
}
public void setIdpeople(String idpeople) {
this.idpeople = idpeople;
}
public String getIduser() {
return iduser;
}
public void setIduser(String iduser) {
this.iduser = iduser;
}
public String getIdmember() {
return idmember;
}
public void setIdmember(String idmember) {
this.idmember = idmember;
}
public ArrayList<String> getMessages() {
return messages;
}
public void setMessages(ArrayList<String> messages) {
this.messages = messages;
}
public ArrayList<String> getAsecs() {
return asecs;
}
public void setAsecs(ArrayList<String> asecs) {
this.asecs = asecs;
}
}
my out put that look like
gson(21917): {"asecs":["asec 1","asec 2","asec 3"],"messages":["msg 1","msg 2","msg 3"]}
gson new(21917): [{"asecs":[],"idmember":"hi","iduser":"hello","messages":[]},{"asecs":[],"idmember":"hi","iduser":"hello","messages":[]},{"asecs":[],"idmember":"hi","iduser":"hello","messages":[]},{"asecs":[],"idmember":"hi","iduser":"hello","messages":[]},{"asecs":[],"idmember":"hi","iduser":"hello","messages":[]}]
my out put should look like
gson new(21917): [{"idmember":"hi","iduser":"hello"},{"idmember":"hi","iduser":"hello"},{"idmember":"hi","iduser":"hello"},{"idmember":"hi","iduser":"hello"},{"idmember":"hi","iduser":"hello"}]
my question is
1)If the gson will display all the object that declare in the class then why the idpeople is not display only arraylist is displayed to my json
2)Should i need to create a separate object file for the Arraylist or any alter coding for my coding
whatever the JsonStructure will contain, all that will be part of your json. if you dont want to include it in your json remove it from class.
I personally think it is not going to harm anyone if your json will contain any extra field and that field is useful for you.
Creating an new class -
JsonStructure oAllergy_Data = new JsonStructure();
will allow your arraylist to be a part of your json. if you dont want it to include, make it separate from JsonStructure class.
Or As an alternative Json can be created like this -
JSONObject outer = new JSONObject();
try {
// field
outer.put("EMAIL", reqModel.getEmail());
// field
outer.put("PASSWORD", reqModel.getPassword());
} catch (JSONException e) {
//
} catch (Exception e) {
//
}
return outer.toString();
remove this line
ArrayList<String> messages = new ArrayList<String>();
ArrayList<String> asecs = new ArrayList<String>();
Use
ArrayList<String> messages ;
ArrayList<String> asecs;
only
I'm new in Android programming's world and I've some problems using JSON to serialize and deserialize an ArrayList of custom objects. I know how to serialize an object, but not if it has an ArrayList as a field.
I found the GSON library but I don't really know how to use it.
I have an ArrayList of a class A which has an ArrayList of a class B. I'm serializing class A using a toJSON() method:
public class A
{
//Some fields like title, id...
private String mTitle;
private ArrayList<B> mArray; //I don't know how to serialize/deserialize this field
public A(){...}
public A(JSONObject json){...}
public JSONObject toJSON() throws JSONException //method I use to convert my object into a JSONObject
{
JSONObject json = new JSONObject();
json.put("TITLE",mTitle);
return json;
}
}
public class B
{
//some fields like a double, String...
public B(){...}
}
In case of collection, you must specify the type.
See a Guide User
In your case, I think this will solve:
Type collectionType = new TypeToken<Collection<A>>(){}.getType();
Collection<A> list = gson.fromJson(json, collectionType);
Where A is your class.
Are you trying to use Parcelable? Try something like this (pseudo code):
public class ParcelableObject implements Parcelable{
List<ObjectB> _customObjectList = new ArrayList<ObjectB>();
#Override
public void writeToParcel(Parcel outParcel_, int arg1) {
outParcel_.writeTypedList(_customObjectList); //where _customObjectList is your list variable
}
//Then in your constructor which takes in a Parcel:
public ParcelableObject(Parcel parcelIn_) {
parcelIn_.readTypedList(_customObjectList, ObjectB.CREATOR);
}
}
ObjectB
public class ObjectB implements Parcelable{
int _randomInt;
public static final Parcelable.Creator<ObjectB> CREATOR = new Parcelable.Creator<ObjectB>() {
#Override
public ObjectBcreateFromParcel(Parcel in) {
return new ObjectB(in);
}
#Override
public ObjectB[] newArray(int size) {
return new ObjectB[size];
}
};
public ObjectB(Parcel parcelIn_) {
_randomInt = parcelIn_.readInt();
}
#Override
public void writeToParcel(Parcel out_, int flags) {
out_.writeInt(_randomInt);
}
}
What is better is to do something like that:
List<YourObject> myList = new Genson().deserialize(dta.toString(), List.class);