[{
"description":"My expense to others",
"items":["aaa","bbb"],
"name":"My Expense"
},
{
"description":"My expense to others","
items":["aaa","bbb"],
"name":"My Expense"
}]
Kotlin Code
val gson = GsonBuilder().create()
val Model= gson.fromJson(body,Array<GroupModel>::class.java).toList()
Gradle
implementation 'com.google.code.gson:gson:2.8.5'
Answer from BIS Tech on Stack Overflow[{
"description":"My expense to others",
"items":["aaa","bbb"],
"name":"My Expense"
},
{
"description":"My expense to others","
items":["aaa","bbb"],
"name":"My Expense"
}]
Kotlin Code
val gson = GsonBuilder().create()
val Model= gson.fromJson(body,Array<GroupModel>::class.java).toList()
Gradle
implementation 'com.google.code.gson:gson:2.8.5'
I have found a solution that is actually working on Android with Kotlin for parsing JSON arrays of a given class. The solution of @Aravindraj didn't really work for me.
val fileData = "your_json_string"
val gson = GsonBuilder().create()
val packagesArray = gson.fromJson(fileData , Array<YourClass>::class.java).toList()
So basically, you only need to provide a class (YourClass in the example) and the JSON string. GSON will figure out the rest.
The Gradle dependency is:
implementation 'com.google.code.gson:gson:2.8.6'
Try this code for deserialize list
val gson = Gson()
val itemType = object : TypeToken<List<Item>>() {}.type
itemList = gson.fromJson<List<Item>>(itemListJsonString, itemType)
You can define a inline reified extension function like:
internal inline fun <reified T> Gson.fromJson(json: String) =
fromJson<T>(json, object : TypeToken<T>() {}.type)
And use it like:
val itemList: List<Item> = gson.fromJson(itemListJsonString)
By default, types are erased at runtime, so Gson cannot know which kind of List it has to deserialize. However, when you declare the type as reified you preserve it at runtime. So now Gson has enough information to deserialize the List (or any other generic Object).
Videos
This can be done without GSON or any other third party library:
@Throws(JSONException::class)
fun JSONObject.toMap(): Map<String, Any> {
val map = mutableMapOf<String, Any>()
val keysItr: Iterator<String> = this.keys()
while (keysItr.hasNext()) {
val key = keysItr.next()
var value: Any = this.get(key)
when (value) {
is JSONArray -> value = value.toList()
is JSONObject -> value = value.toMap()
}
map[key] = value
}
return map
}
@Throws(JSONException::class)
fun JSONArray.toList(): List<Any> {
val list = mutableListOf<Any>()
for (i in 0 until this.length()) {
var value: Any = this[i]
when (value) {
is JSONArray -> value = value.toList()
is JSONObject -> value = value.toMap()
}
list.add(value)
}
return list
}
Usage to convert JSONArray to List:
val jsonArray = JSONArray(jsonArrStr)
val list = jsonArray.toList()
Usage to convert JSONObject to Map:
val jsonObject = JSONObject(jsonObjStr)
val map = jsonObject.toMap()
More info is here
Use this code:
import com.google.gson.annotations.SerializedName
import com.google.gson.Gson
data class Array(
@SerializedName("message")
var message: String,
@SerializedName("name")
var name: String,
@SerializedName("creation")
var creation: String
)
data class Example(
@SerializedName("array")
var array: List<Array>? = null
)
private fun fromJson(json:String):Example{
return Gson().fromJson<Example>(json, Example::class.java)
}
PS: I made it with this site:http://www.jsonschema2pojo.org/
You need to change parameter in your fromJson() function call like following:
val weatherList: List<WeatherObject> = gson.fromJson(stringReader , Array<WeatherObject>::class.java).toList()
You need to pass Array<WeatherObject>::class.java for class type and then convert result into List. No need to change registerTypeAdapter() function call.
Check following code:
fun getWeatherObjectFromJson(jsonStr: String): List<WeatherObject> {
var stringReader: StringReader = StringReader(jsonStr)
var jsonReader: JsonReader = JsonReader(stringReader)
val gsonBuilder = GsonBuilder().serializeNulls()
gsonBuilder.registerTypeAdapter(WeatherObject::class.java, WeatherDeserializer())
val gson = gsonBuilder.create()
val weatherList: List<WeatherObject> = gson.fromJson(stringReader , Array<WeatherObject>::class.java).toList()
return weatherList
}
an alternative extension function:
inline fun <reified T> Gson.fromJson(json: String) = fromJson<T>(json, object : TypeToken<T>() {}.type)
usage:
val str ="[....]"
val list:List<WeatherObject> = Gson().fromJson<List<WeatherObject>>(str)
You could try doing this instead:
val objectList = gson.fromJson(json, Array<SomeObject>::class.java).asList()
EDIT [14th January 2020]: You should NOT be using GSON anymore. Jake Wharton, one of the projects maintainers, suggests using Moshi, Jackson or kotlinx.serialization.
Try this, it uses object instead of Type..
measurements : List<SomeOjbect> = gson.fromJson(text, object : TypeToken<List<SomeOjbect>>() {}.type)
You can parse the JSONArray directly, don't need to wrap your Post class with PostEntity one more time and don't need new JSONObject().toString() either:
Gson gson = new Gson();
String jsonOutput = "Your JSON String";
Type listType = new TypeToken<List<Post>>(){}.getType();
List<Post> posts = gson.fromJson(jsonOutput, listType);
I was looking for a way to parse object arrays in a more generic way; here is my contribution:
CollectionDeserializer.java:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class CollectionDeserializer implements JsonDeserializer<Collection<?>> {
@Override
public Collection<?> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
Type realType = ((ParameterizedType)typeOfT).getActualTypeArguments()[0];
return parseAsArrayList(json, realType);
}
/**
* @param serializedData
* @param type
* @return
*/
@SuppressWarnings("unchecked")
public <T> ArrayList<T> parseAsArrayList(JsonElement json, T type) {
ArrayList<T> newArray = new ArrayList<T>();
Gson gson = new Gson();
JsonArray array= json.getAsJsonArray();
Iterator<JsonElement> iterator = array.iterator();
while(iterator.hasNext()){
JsonElement json2 = (JsonElement)iterator.next();
T object = (T) gson.fromJson(json2, (Class<?>)type);
newArray.add(object);
}
return newArray;
}
}
JSONParsingTest.java:
public class JSONParsingTest {
List<World> worlds;
@Test
public void grantThatDeserializerWorksAndParseObjectArrays(){
String worldAsString = "{\"worlds\": [" +
"{\"name\":\"name1\",\"id\":1}," +
"{\"name\":\"name2\",\"id\":2}," +
"{\"name\":\"name3\",\"id\":3}" +
"]}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Collection.class, new CollectionDeserializer());
Gson gson = builder.create();
Object decoded = gson.fromJson((String)worldAsString, JSONParsingTest.class);
assertNotNull(decoded);
assertTrue(JSONParsingTest.class.isInstance(decoded));
JSONParsingTest decodedObject = (JSONParsingTest)decoded;
assertEquals(3, decodedObject.worlds.size());
assertEquals((Long)2L, decodedObject.worlds.get(1).getId());
}
}
World.java:
public class World {
private String name;
private Long id;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
put adds the list as an element to the JSONArray. Thats not what you want. You want your JSONArray to represent the list.
JSONArray offers a constructor for that:
val jsonArray = JSONArray(listOf(1, 2, 3))
But there is a much easier way. You don't need to worry about single properties. Just pass the whole POJO.
Let's say you have this:
class QuoteData(val id: Int, val quoteId: Int, travellerId: Int?)
class TravelerData(val userQuoteTravellers: List<QuoteData>)
val travelerData = TravelerData(listOf(QuoteData(1354, 546, null)))
You just have to pass travelerData to the JSONArray constructor:
val travelerDataJson = JSONArray(travelerData)
and it will be represented like this:
"userQuoteTravellers": [ { "id": 1354, "quoteId": 526, "travellerId": null } ]
With Dependencies
Add to your gradle:
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
Convert ArrayList to JsonArray
val jsonElements = (JsonArray) new Gson().toJsonTree(itemsArrayList)
Without Dependencies
val jsonElements = JSONArray(itemsArrayList)
Create this inline fun:
inline fun <reified T> Gson.fromJson(json: String) = fromJson<T>(json, object: TypeToken<T>() {}.type)
and then you can call it in this way:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
Previous Alternatives:
ALTERNATIVE 1:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
You have to put object : and the specific type in fromJson<List<Turns>>
ALTERNATIVE 2:
As @cypressious mention it can be achieved also in this way:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
use as:
val turnsType = genericType<List<Turns>>()
This solves the problem:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
The first line creates an object expression that descends from TypeToken and then gets the Java Type from that. Then the Gson().fromJson method either needs the type specified for the result of the function (which should match the TypeToken created). Two versions of this work, as above or:
val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)
To make it easier to create the TypeToken you can create a helper function, which is required to be inline so that it can use reified type parameters:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Which can then be used in either of these ways:
val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()
And the whole process can be wrapped into an extension function for the Gson instance:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
So that you can just call Gson and not worry about the TypeToken at all:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
Here Kotlin is using type inference from one side of the assignment or the other, and reified generics for an inline function to pass through the full type (without erasure), and using that to construct a TypeToken and also make the call to Gson