moshi
A modern JSON library for Android and Java.
This question already has an answer here:
Is it possible to get something similar to Class<List<Data>>.class
? I read you can't call .class
because of how it works interanlly, so I was wondering if maybe using something similar to new ArrayList<Data>().getClass()
might work? That one in particular doesn't work as the returned class is Class<? extends List<Data>>
so I'm out of options, is it even possible?
Context: I'm trying to parse a List<Data>
using square/moshi but the library seems to be on alpha so there is no documentation on it.
Source: (StackOverflow)
I have a User class. And two subclasses. Parent and Child.
I get json from my server with {"user":"..."} and need to convert it to parent or to child depending on user.type
As I understand I need to add custom converter this way:
Moshi moshi = new Moshi.Builder()
.add(new UserAdapter())
.build();
Here's my implementation of UserAdapter. I know it's dummy, but it's not working even this way:
public class UserAdapter {
@FromJson
User fromJson(String userJson) {
Moshi moshi = new Moshi.Builder().build();
try {
JSONObject jsonObject = new JSONObject(userJson);
String accountType = jsonObject.getString("type");
switch (accountType) {
case "Child":
JsonAdapter<Child> childJsonAdapter = moshi.adapter(Child.class);
return childJsonAdapter.fromJson(userJson);
case "Parent":
JsonAdapter<Parent> parentJsonAdapter = moshi.adapter(Parent.class);
return parentJsonAdapter.fromJson(userJson);
}
} catch (JSONException | IOException e) {
e.printStackTrace();
}
return null;
}
@ToJson
String toJson(User user) {
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<User> jsonAdapter = moshi.adapter(User.class);
String toJson = jsonAdapter.toJson(user);
return toJson;
}
First of all I get following exception with this code.
com.squareup.moshi.JsonDataException: Expected a string but was BEGIN_OBJECT at path $.user
And second, I believe there's a better way to do it. Please advice.
Upd. here's stacktrace for the error:
com.squareup.moshi.JsonDataException: Expected a name but was BEGIN_OBJECT at path $.user
at com.squareup.moshi.JsonReader.nextName(JsonReader.java:782)
at com.squareup.moshi.ClassJsonAdapter.fromJson(ClassJsonAdapter.java:141)
at com.squareup.moshi.JsonAdapter$1.fromJson(JsonAdapter.java:68)
at com.squareup.moshi.JsonAdapter.fromJson(JsonAdapter.java:33)
at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:33)
at retrofit.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:23)
at retrofit.OkHttpCall.parseResponse(OkHttpCall.java:148)
at retrofit.OkHttpCall.execute(OkHttpCall.java:116)
at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:111)
at retrofit.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:88)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable.unsafeSubscribe(Observable.java:7710)
at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Source: (StackOverflow)
I use Moshi to deserialize the following JSON file:
{
"display": "Video 1",
"isTranslated": false,
"videoSize": [
1920,
1080
]
}
... using the following model class:
public class Stream {
public final String display;
public final boolean isTranslated;
public final int[] videoSize;
public Stream(String display,
boolean isTranslated,
int[] videoSize) {
this.display = display;
this.isTranslated = isTranslated;
this.videoSize = videoSize;
}
}
This works as expected.
Now, I would like to replace the int[]
with a dedicated VideoSize
class which maps the two integer values into named fields such as:
public class VideoSize {
public final int height;
public final int width;
public VideoSize(int width, int height) {
this.height = height;
this.width = width;
}
}
Is this possible with a custom type adapter or somehow else?
Source: (StackOverflow)