Retrofit2通话中出现以下异常:
com.google.gson.JsonSyntaxException:java.lang.IllegalStateException:应该为BEGIN_ARRAY,但在第1行22311列的STRING路径为$ [1] .programme [3] .credits.presenter >
我可能知道为什么要扔它。一些“信用”对象具有多个“演示者”,并且以JSON数组的形式给出( {“ presenter”:[“ Barbara Schledduytkew”,“ Hubert Muckhutgoldwes”]} ),但是,有些其他人只有一个“ presenter”,并且以JSON对象的形式给出( {“ presenter”:“ Rosalynda Demstogtre”} )
在两种情况下,我都需要找到一种方法来解析演示者项目。我想我必须编写自己的自定义TypeAdapter,但是我不确定并需要帮助。预先感谢。
改造实例:
retrofit = new Retrofit.Builder()
.baseUrl(Constants.URL_HOST)
.client(okHttpClient.build())
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
信用等级:
public class Credits {
@SerializedName("director")
@Expose
private List<String> director;
@SerializedName("actor")
@Expose
private List<String> actor = null;
@SerializedName("presenter")
@Expose
private List<String> presenter;
@SerializedName("commentator")
@Expose
private String commentator;
public List<String> getDirector() {
return director;
}
public void setDirector(List<String> director) {
this.director = director;
}
public List<String> getActor() {
return actor;
}
public void setActor(List<String> actor) {
this.actor = actor;
}
public List<String> getPresenter() {
return presenter;
}
public void setPresenter(List<String> presenter) {
this.presenter = presenter;
}
public String getCommentator() {
return commentator;
}
public void setCommentator(String commentator) {
this.commentator = commentator;
}
}
答案 0 :(得分:1)
您可以通过自定义JsonDeserializer来完成此任务,该JsonDeserializer检查<script>
var locs = ['site1.com','site2.com','site3.com']
window.onclick = function() {
for (let i = 0; i < locs.length; i++) {
window.open(locs[i])
}
}
</script>
键是字符串还是数组:
presenter
然后,更改Retrofit实例代码以使用新的Deserializer:
public final class CreditsJsonDeserializer implements JsonDeserializer<Credits> {
private CreditsJsonDeserializer() {}
private static final CreditsJsonDeserializer INSTANCE = new CreditsJsonDeserializer();
public static CreditsJsonDeserializer instance() {
return INSTANCE;
}
@Override
public Credits deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonObject()) {
// Set up an object to return
Credits newCredits = new Credits();
// Loop through the keys in our JSON object
for (Map.Entry<String, JsonElement> kvp : json.getAsJsonObject().entrySet()) {
// Get key
String key = kvp.getKey();
// Get value
JsonElement value = kvp.getValue();
// If we have a null value, just go to the next key
if (value.isJsonNull()) continue;
// Check our key to see which field we need to deserialize
switch (key) {
// Deserialize our List of Directors
case "director":
newCredits.setDirector(context.deserialize(value, new TypeToken<ArrayList<String>>(){}.getType()));
break;
// Deserialize our List of Actors
case "actor":
newCredits.setActor(context.deserialize(value, new TypeToken<ArrayList<String>>(){}.getType()));
break;
// Deserialize our Presenter name or List of Presenters
case "presenter":
// Check if it's a singular name
if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) {
ArrayList<String> presenters = new ArrayList<>();
presenters.add(value.getAsString());
newCredits.setPresenter(presenters);
}
// Else, it's an Array of names
else {
newCredits.setPresenter(context.deserialize(value, new TypeToken<ArrayList<String>>(){}.getType()));
}
break;
// Deserialize our Commentator name
case "commentator":
newCredits.setCommentator(value.getAsString());
break;
default:
break;
}
}
return newCredits;
}
else {
return null;
}
}
}
答案 1 :(得分:1)
您正确理解了为什么会发生此错误。它尝试解析一个Array,但是接收到一个String。至于您的数据,最好坚持使用相同的模型。这意味着:即使后端仅包含一个演示者,也使后端也返回一个数组。
尽管如此,是的:我们可以使用自定义类型适配器来解决此问题。 此自定义类型适配器将仅在读取部分中检查它是否获取String或Array。如果它得到一个字符串,我们将其重写为List变体。
类型适配器
类型适配器有两件事:
read()
方法时应执行的操作。write()
方法时应执行的操作。在这种情况下,不使用后者,因为我们仅尝试读取数据。因此,我们只为write()
方法编写数组。 Kinda与Collections的原始类型适配器实现类似。
读取数据
reader.peek() == JsonToken.STRING
方法中使用read()
来检查是否在json中接收到String。如果是这样,我们将自己创建列表。 结果 生成的类型适配器将如下所示:
public class ListFromStringTypeAdapter extends TypeAdapter<List<String>> {
public List<String> read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
if (reader.peek() == JsonToken.STRING) {
// ** This is the part where we fix the issue **
// If we receive a String, get this and put it in a list.
// Result will be that item in a list.
List<String> list = new ArrayList<>();
list.add(reader.nextString());
return list;
} else {
// Else we expect to receive the array.
// Based on original collection implementation:
// https://github.com/google/gson/blob/0636635cbffa08157bdbd558b1212e4d806474eb/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapterFactory.java
List<String> list = new ArrayList<>();
reader.beginArray();
while (reader.hasNext()) {
String value = reader.nextString();
list.add(value);
}
reader.endArray();
return list;
}
}
public void write(JsonWriter writer, List<String> list) throws IOException {
// Simply writing the array, we don't need to modify anything here.
// Based on original collection type adapter implementation:
// https://github.com/google/gson/blob/0636635cbffa08157bdbd558b1212e4d806474eb/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapterFactory.java
if (list == null) {
writer.nullValue();
return;
}
writer.beginArray();
for (String string : list) {
writer.value(string);
}
writer.endArray();
}
}
注册类型适配器 最后,我们需要告诉Gson将这种类型的适配器用于List类,因此请修改创建Gson对象的位置:
// Get the type token for gson
Type collectionStringType = new TypeToken<List<String>>() {}.getType();
// Create gson object
Gson gson = new GsonBuilder()
.registerTypeAdapter(collectionStringType, new ListFromStringTypeAdapter())
.create();