Deserialize classes with same interface using GSON - java

I have an interface (called Content) and a couple of classes that implement that interface (e.g. ContentVideo, ContentAd...). I receive a JSON Object that contains a list of those objects. I started out deserializing those objects manually in seperate classes, but recently came across GSON, which would simplify this process immensely. But I'm not sure how to implement this.
Here's ContentVideoJSONParser
public ArrayList<ContentVideo> parseJSON(String jsonString) {
ArrayList<ContentVideo> videos = new ArrayList<>();
JSONArray jsonArr = null;
Gson gson = new Gson();
try {
jsonArr = new JSONArray(jsonString);
for(int i = 0; i < jsonArr.length(); i++) {
JSONObject jsonObj = jsonArr.getJSONObject(i);
ContentVideo cv = gson.fromJson(jsonObj.toString(), ContentVideo.class);
videos.add(cv);
}
} catch (JSONException e) {
e.printStackTrace();
}
return videos;
}
ContentAdJSONParser looks exactly the same, except for returning an ArrayList of ContentAd objects and this line to retrieve the object:
ContentAd ca = gson.fromJson(jsonObj.toString(), ContentAd.class);
What's the easiest way to combine those to classes into one? Note: one JSON object only contains one class, either ContentVideo or ContentAd. They are not mixed like in other SO questions, which would require a TypeAdapter.
This seems to be a straightforward problem but I can't figure it out. Thanks for your help.

Something like this perhaps?
public <T extends Content> ArrayList<T> parseJSON(String jsonString, Class<T> contentClass) {
ArrayList<T> contents = new ArrayList<>();
JSONArray jsonArr = null;
Gson gson = new Gson();
try {
jsonArr = new JSONArray(jsonString);
for(int i = 0; i < jsonArr.length(); i++) {
JSONObject jsonObj = jsonArr.getJSONObject(i);
T content = gson.fromJson(jsonObj.toString(), contentClass);
contents.add(content);
}
} catch (JSONException e) {
e.printStackTrace();
}
return contents;
}

Related

How to generate JsonArray correctly?

I am developing a java application in android studio and a Rest web server in java, netbeans.
I need to send a JSON to the server ...
I did the whole engine the webService and tested it using Postman.
The Json used was this:
{
"id":0,
"ticket":"2132158645161654561651616",
"avaliacoes":[
{
"idAvaliacao":1,
"nota":5,
"observacao":"testeTEste"
},
{
"idAvaliacao":2,
"nota":4,
"observacao":"testeTEste"
}
]
}
Worked perfectly.
So I went to generate Json dynamically in the application:
public void enviaDadosVenda(){
JSONObject obj = new JSONObject();
JSONArray avaliacoes = new JSONArray();
JSONObject avaliacao;
try {
obj.put("id", 0);
obj.put("ticket", PrincipalActivity.ticket_id);
for(int i=0; i < PrincipalActivity.listAval.size();i++){
avaliacao = new JSONObject();
avaliacao.put("idAvaliacao", listAval.get(i).getId());
avaliacao.put("nota", listAval.get(i).getNota());
avaliacao.put("observacao", listAval.get(i).getObservacoes());
avaliacoes.add(avaliacao);
}
obj.put("avaliacoes", avaliacoes);
} catch (JSONException e) {
e.printStackTrace();
}
}
The generated Json is this:
{
"id":0,
"ticket":"2132158645161654561651616",
"avaliacoes":"[
{
\"idAvaliacao\":1,
\"nota\":5,
\"observacao\":\"testeTEste\"
},
{
\"idAvaliacao\":2,
\"nota\":4,\"observacao\":\"testeTEste\"
}
]"
}
If I use this second Json on Postman the webService no gets it correctly.
Get the id and the ticket, but the evaluations array gets a single item(avaliacoes.get(0)) = null.
I've looked at other posts about Json and ArrayJsons and nothing helped me ...
Parsing JSON Object in Java
Convert JsonObject to String
How to create correct JSONArray in Java using JSONObject
https://pt.stackoverflow.com/questions/140442/reconhecer-um-jsonobject-ou-jsonarray
Just replace avaliacoes.add(avaliacao); with avaliacoes.put(avaliacao);
public void enviaDadosVenda(){
JSONObject obj = new JSONObject();
JSONArray avaliacoes = new JSONArray();
JSONObject avaliacao;
try {
obj.put("id", 0);
obj.put("ticket", "DemoActivity.ticket_id");
for(int i=0; i < 2;i++){
avaliacao = new JSONObject();
avaliacao.put("idAvaliacao", "1");
avaliacao.put("nota", "nota");
avaliacao.put("observacao", "observacao");
avaliacoes.put(avaliacao);
}
obj.put("avaliacoes", avaliacoes);
Log.d("DEMO", obj.toString()); // {"id":0,"ticket":"DemoActivity.ticket_id","avaliacoes":[{"idAvaliacao":"1","nota":"nota","observacao":"observacao"},{"idAvaliacao":"1","nota":"nota","observacao":"observacao"}]}
} catch (JSONException e) {
e.printStackTrace();
}
}
For best practice use Gson

Hashmap clear values

I have this code. When i clear ArrayList, values in HashMap clear too. How can i save data?
public class Stations extends AppCompatActivity {
public static Map<String, ArrayList<String>> cities = new HashMap<>();
...
public void parseFrom() {
cities.clear();
ArrayList<String> citiesList = new ArrayList<>();
try {
JSONObject jObject = new JSONObject(loadJSON());
JSONArray jArray = jObject.getJSONArray("citiesFrom");
String countryTitle = null;
for (int i = 0; i < jArray.length(); i++) {
JSONObject jsonObject = jArray.getJSONObject(i);
if ((countryTitle != null) && (!countryTitle.equals(jsonObject.getString("countryTitle")))) {
cities.put(countryTitle, citiesList);
citiesList.clear();
}
countryTitle = jsonObject.getString("countryTitle");
citiesList.add(jsonObject.getString("cityTitle"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
When I use citiesList.clear();all values are clearing, but keys still "alive".
This is because they have the same reference in memory.
Try doing this:
cities.put(countryTitle, new ArrayList<String>(citiesList));
But, if what you really want is to remove it from the hashmap, you'll have to call cities.remove(countryTitle) instead of only clearing the array of cities.

Get Class Type of Object and use it in a Variable Declaration

What I am trying to do, and I don't know whether this is possible, is to get the class type of an object, and then use it in a declaration. I am using the Gson library for Json Conversion and I want to create a method that can take any object Arraylist type and convert it into a JsonArray. What I have below is code. Arraylist of type X will are casted down to type Object and than passed to the method below. The INSERT_CLASS_HERE should be dynamic based on the Object type.
public static JsonArray getJsonArray(List<Object> list , Class theClass){
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(list, new TypeToken<List<INSERT_CLASS_TYPE_HERE>>() {}.getType());
if (! element.isJsonArray()) {
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
JsonArray jsonArray = element.getAsJsonArray();
return jsonArray;
}
What I tried was the following but this isn't correct syntax and will throw errors
public static JsonArray getJsonArray(List<Object> list , Class theClass){
if(list.size() == 0) return null;
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(list, new TypeToken<List<theClass>>() {}.getType());
if (! element.isJsonArray()) {
// fail appropriately
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
JsonArray jsonArray = element.getAsJsonArray();
return jsonArray;
}
1) Is this possible to do, and if not why not?
2) If it is not, how can this be achieved?
Thank you!
Why are you passing in a type value? That should not be required.
public static JsonArray getJsonArray(List<Object> list){
if(list.size() == 0) return null;
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(list);
JsonArray jsonArray = element.getAsJsonArray();
return jsonArray;
}
Better yet to avoid casting you can do the following
public static <T> JsonArray getJsonArray(List<T> list){
if(list.size() == 0) return null;
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(list);
JsonArray jsonArray = element.getAsJsonArray();
return jsonArray;
}
It seems what you are trying to do is along the lines of Java generics.
This should be fairly simply to do using generics:
public static <T> JsonArray getJsonArray(List<T> list){
if(list.size() == 0) return null;
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(list, new TypeToken<List<T>>() {}.getType());
//Not familiar with gson, but you might be able to just use T here instead
Try modifying your method signature like this:
public static <T> JsonArray getJsonArray(List<Object> list, Class<T> theClass )
You should then be able to do this:
new TypeToken<List<T>>

Faster way to parse a JSON String in android

I'm using this method to parse a JSON string, but it is too slow... is there a better way to do it?
Thanks
synchronized private void parseCategories(String response){
try{
JSONArray categoriesJSONArray = new JSONArray (response);
// looping through All Contacts
for(int i = 0; i < categoriesJSONArray.length(); i++){
JSONObject currentCategory = categoriesJSONArray.getJSONObject(i);
String label="";
String categoryId="";
// Storing each json item in variable
if(currentCategory.has("label"))
label = currentCategory.getString("label");
if(currentCategory.has("id"))
categoryId = currentCategory.getString("id");
if(
label!=null &&
categoryId!=null
)
{
Category toAdd = new Category(categoryId, label);
categories.add(toAdd);
}
}
//Alphabetic order
Collections.sort(
categories,
new Comparator<Feed>() {
public int compare(Feed lhs, Feed rhs) {
return lhs.getTitle().compareTo(rhs.getTitle());
}
}
);
Intent intent = new Intent("CategoriesLoaded");
LocalBroadcastManager.getInstance(mAppContext).sendBroadcast(intent);
}catch (JSONException e) {
e.printStackTrace();
}
}
Here's try following code to start with. You would need Gson library for it.
Gson gson=new Gson();
MyBean myBean=gson.fromJson(response);
Note: Here MyBean class contains the fields present in you json string for e.g. id, along with getter and setters. Rest of all is handled by Gson.
Here's a quick demo.
import com.google.gson.annotations.SerializedName;
public class Box {
#SerializedName("id")
private String categoryId;
// getter and setter
}
Say you JSON looks as following:
{"id":"A12"}
You can parse it as follows:
class Parse{
public void parseJson(String response){
Gson gson=new Gson();
Box box=gson.fromJson(response,Box.class);
System.out.println(box.getCategoryId());
}
}
Output :
A12
For more on Gson visit here
Use GSON library. You can convert your object to json string like the following example:
MyClass MyObject;
Gson gson = new Gson();
String strJson = gson.toJson(MyObject);

How can i use a constructor of a generic class

i got multiple classes which do basicly the same. I pass a JSONObject in the constructor an it sets some variabes.
Now i got some other classes which create those first classes and add them to a ArrayList. Now i want to merge the second classes to one using generics.
This is what I want to do:
public class Data<T> {
public ArrayList<T> data;
public Data(String response1) {
data = new ArrayList<T>();
JSONArray ja;
try {
ja = new JSONArray(response1);
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = (JSONObject) ja.get(i);
data.add(new T(jo));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
but it doesnt let me create an Instance of T with
new T(jo);
Would be nice if someone can help me
There is a standard trick for this situations: pass Class<T> along with the String data into the call, and add a setter for the JSONObject. This would let you call a parameterless constructor, like this:
interface WithJson {
void setJson(JSONObject jo);
}
public class Data<T extends WithJson> {
public Data(String response1, Class<T> type) {
data = new ArrayList<T>();
JSONArray ja;
try {
ja = new JSONArray(response1);
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = (JSONObject) ja.get(i);
T obj = type.newInstance();
object.setJson(jo);
data.add(obj);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
The Class<T> has been modified in Java 5 to let you use it as a factory for the instances of that class. The call of type.newInstance is checked statically for type safety. The addition of the interface WithJson lets you call setJson method on the instances of T in a way that the compiler can check statically.
When you construct Data<T>, you need to pass the class being created, like this:
Data<MyContent> d = new Data(jsonString, MyContent.class);
Use a generic factory interface.
public interface Factory<T>
{
public T createFromJSONObject( JSONObject jo );
}
And now a modified constructor:
public Data(
String response1,
Factory<T> factory
) {
data = new ArrayList<T>();
JSONArray ja;
try {
ja = new JSONArray(response1);
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = (JSONObject) ja.get(i);
data.add( factory.createFromJSONObject( jo ) );
}
} catch (JSONException e) {
e.printStackTrace();
}
}

Categories