5
\$\begingroup\$

I consume an API which gives me this type of JSON:

{
 "data": {
 "name": "Start",
 "pid": "1",
 "position": {
 "data": {
 "x": "31",
 "y": "330"
 },
 "metadata": "empty"
 }
 },
 "metadata": "empty"
}

I have created the classes with objects with the same structure as the above JSON. I use the retrofit lib in Android which inside uses GSON for parsing the JSON.

My model classes would be like this:

MResponse.class

public class MResponse {
 @SerializedName("data")
 public User user;
 String metadata;
}

User.class

public class User {
 public String name;
 public String pid;
 @SerializedName("position")
 public PositionData positionData;
}

PositionData.class

public class PositionData {
 @SerializedName("data")
 public Position position;
 public String metadata;
}

Position.class

public class Position {
 public String x;
 public String y;
}

Now this works fine for me. But as you can see for every model I have to create a parent which will have the same structure just changes the child. This fact doubles the classes that I use for my models. I would like to ask if there is a better way to avoid all these classes.

I don't want to use inner classes. I was thinking that the guys that have done the JSON like this must have had a reason why they did it like this and also a way to make the parsing more easier.

Usually I was used to parse this kind of JSON structure:

{
 "data": {
 "name": "Start",
 "pid": "1",
 "position": {
 "x": "31",
 "y": "330"
 }
 }
}

And here it's easier if I would follow the solution above.

EDIT

Also any solution in Kotlin is welcomed

asked Mar 21, 2017 at 9:32
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

You can create a generic container/entity for "data" and "metadata" and reuse it. e.g.:

data class MEntity<T>(
 var data: T? = null,
 var metadata: String? = null
)
data class User(
 var name: String? = null,
 var pid: String? = null,
 var position: MEntity<Position>? = null
)
data class Position(
 var x: String? = null,
 var y: String? = null
)

Due to type erasure you must use a TypeToken to deserialize the JSON into a generic type:

gson.fromJson<MEntity<User>>(json, object : TypeToken<MEntity<User>>() {}.type)

This isn't very convenient but thankfully Kotlin allows us to use reified type parameters to define an extension function to simplify this:

inline fun <reified T> Gson.fromJsonToGeneric(json: String): T {
 return fromJson(json, object : TypeToken<T>() {}.type)
}

Now the usage becomes much simpler:

val userMEntity = gson.fromJsonToGeneric<MEntity<User>>(json)
println(userMEntity)

Output:

MEntity(data=User(name=Start, pid=1, position=MEntity(data=Position(x=31, y=330), metadata=empty)), metadata=empty)
answered Apr 1, 2017 at 14:15
\$\endgroup\$
0
\$\begingroup\$

Well the solution that I was asking for was quite simple in my opinion, I just didn't know it in the beginning. I found this times ago but now I want to write it here. I haven't used the Kotlin solution mentioned from @mfulton but I think that it's also the right answer.

Based on source code of Retrofit and some other related answers about Java generics this was the answer for my problem:

public class DataResponse<T, R> {
 public T data;
 @SerializedName("meta")
 public R metadata;
}

and this is an example how I can use it:

Observable<DataResponse<User, BaseMeta>> getUser()

For me this was the solution. If there are better solution out there, I am ready to accept them.

answered Apr 12, 2017 at 8:58
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.