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

\$\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) 
    \$\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.

      \$\endgroup\$

        Start asking to get answers

        Find the answer to your question by asking.

        Ask question

        Explore related questions

        See similar questions with these tags.