美好的一天。理解这一点我有点麻烦。我有一个看起来像这样的JSON:
{
"data": [
{
"id": "43",
"type": "position",
"attributes": {
"address-id": "1",
"employer-id": "11"
}
}
],
"included": [
{
"id": "1",
"type": "address",
"attributes": {
"line-1": "21 london london",
"line-2": "",
"line-3": "",
"locality": "",
"region": "London",
"post-code": "",
"country": "UK",
"latitude": "",
"longitude": ""
}
},
{
"id": "11",
"type": "employer",
"attributes": {
"title": "Mr",
"first-name": "S",
"last-name": "T"
}
}
]
}
我的Retrofit电话是:
@GET("/api/positions")
Single<PositionResponse> getPosition();
我的PositionResponse
课程:
public class PositionResponse {
@SerializedName("data")
@Expose
private List<DataResponse> data;
@SerializedName("included")
@Expose
private List<IncludedModel> included;
public List<DataResponse> getData() {
return data;
}
public void setData(List<DataResponse> data) {
this.data = data;
}
public List<IncludedModel> getIncluded() {
return included;
}
public void setIncluded(List<IncludedModel> included) {
this.included = included;
}
}
}
现在想象它有更多的数据。如何创建自定义TypeAdapter
或JsonDeserializer
来解析List<IncludedModel>
?出于某种原因,我可以为JsonDeserializer
创建自定义TypeAdapter
或Object
,但是当涉及List
时,我似乎无法得到那个工作。
我的TypeAdapter
如下:
public class IncludedTypeAdapter extends TypeAdapter<ArrayList<IncludedModel>> {
@Override
public void write(JsonWriter out, ArrayList<IncludedModel> value) throws IOException {
}
@Override
public ArrayList<IncludedModel> read(JsonReader in) throws IOException {
ArrayList<IncludedModel> list = new ArrayList<>();
IncludedModel model = new IncludedModel();
Gson gson = new Gson();
in.beginArray();
String id = null;
//in.beginObject();
while(in.hasNext()){
JsonToken nextToken = in.peek();
if(JsonToken.BEGIN_OBJECT.equals(nextToken)){
in.beginObject();
} else if(JsonToken.NAME.equals(nextToken)){
if(JsonToken.NAME.name().equals("id")){
id = in.nextString();
model.setId(id);
} else if(JsonToken.NAME.name().equals("type")){
String type = in.nextString();
model.setMytype(type);
switch (type) {
case BaseModelType.Employer:
EmployerResponse employer = gson.fromJson(in, EmployerResponse.class);
model.setEmployer(employer);
break;
}
}
}
}
list.add(model);
return list;
}
我注册了我的Gson:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(IncludeModel.class, new IncludedTypeAdapter());
//gsonBuilder.registerTypeAdapter(new IncludedTypeAdapter());
gsonBuilder.serializeNulls();
Gson gson = gsonBuilder.create();
return gson;
我通过GsonConverterFactory
进行了改造注册。
我得到了:
预期BEGIN_ARRAY但是在第1行第6292行路径为BEGIN_OBJECT $ .included [0]
我怀疑是因为我的改造回复是<PositionResponse>
,这是JsonObject
。
总结我的问题:如何使用我自己的自定义类型适配器反序列化List<IncludeModel>
对象,同时我的Retrofit服务的响应类型为PositionResponse
?非常感谢您的患者和答案。
答案 0 :(得分:1)
如果您使用JsonDeserializer
使用JSON树模型,这很容易。纯类型适配器有点过分(我认为,RuntimeTypeAdapterFactory也是如此,因为它仍然是面向树的),在JSON文档的最简单的情况下你可以使用这样的东西(你可以找到一个my yesterday answer中有类似的方法有更多的解释,但你的情况略有不同)。
我假设你想要这样的映射:
abstract class Element {
final String id = null;
private Element() {
}
static final class Address
extends Element {
@SerializedName("line-1") final String line1 = null;
@SerializedName("line-2") final String line2 = null;
@SerializedName("line-3") final String line3 = null;
@SerializedName("locality") final String locality = null;
@SerializedName("region") final String region = null;
@SerializedName("post-code") final String postCode = null;
@SerializedName("country") final String country = null;
@SerializedName("latitude") final String latitude = null;
@SerializedName("longitude") final String longitude = null;
private Address() {
}
@Override
public String toString() {
return country + " " + region;
}
}
static final class Employer
extends Element {
@SerializedName("title") final String title = null;
@SerializedName("first-name") final String firstName = null;
@SerializedName("last-name") final String lastName = null;
private Employer() {
}
@Override
public String toString() {
return title + ' ' + firstName + ' ' + lastName;
}
}
static final class Position
extends Element {
@SerializedName("address-id") final String addressId = null;
@SerializedName("employer-id") final String employerId = null;
private Position() {
}
@Override
public String toString() {
return '(' + addressId + ';' + employerId + ')';
}
}
}
你所要做的只是:
Gson
;重做所有Gson可以开箱即用:列表和POJO通过反思; JsonToken
如果通过switch
进行检查会更好(顺便说一句,enum
是单身人士,使用引用等式==
)比较它们是完全合法的,等)。所以,它可以通过以下方式实现:
final class ElementJsonDeserializer
implements JsonDeserializer<Element> {
private static final JsonDeserializer<Element> elementJsonDeserializer = new ElementJsonDeserializer();
private ElementJsonDeserializer() {
}
static JsonDeserializer<Element> getElementJsonDeserializer() {
return elementJsonDeserializer;
}
@Override
public Element deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
final JsonObject jsonObject = jsonElement.getAsJsonObject();
final String typeCode = jsonObject.getAsJsonPrimitive("type").getAsString();
final Class<? extends Element> clazz;
switch ( typeCode ) {
case "address":
clazz = Element.Address.class;
break;
case "employer":
clazz = Element.Employer.class;
break;
case "position":
clazz = Element.Position.class;
break;
default:
throw new JsonParseException("Unrecognized type: " + typeCode);
}
reattach(jsonObject, "attributes");
return context.deserialize(jsonElement, clazz);
}
private static void reattach(final JsonObject parent, final String property) {
final JsonObject child = parent.getAsJsonObject(property);
parent.remove(property); // remove after we're sure it's a JSON object
copyTo(parent, child);
}
private static void copyTo(final JsonObject to, final JsonObject from) {
for ( final Entry<String, JsonElement> e : from.entrySet() ) {
to.add(e.getKey(), e.getValue());
}
}
}
当然,您可以重构上述内容以提取策略以实现策略设计模式以重用它。把它们放在一起:
final class Response {
final List<Element> data = null;
final List<Element> included = null;
}
(上面看起来像Map<String, List<Element>>
,但你决定了。)
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(Element.class, getElementJsonDeserializer())
.create();
public static void main(final String... args)
throws IOException {
try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43811168.class, "data.json") ) {
final Response response = gson.fromJson(jsonReader, Response.class);
dump(response.data);
dump(response.included);
}
}
private static void dump(final Iterable<Element> elements) {
for ( final Element e : elements ) {
System.out.print(e.getClass().getSimpleName());
System.out.print(" #");
System.out.print(e.id);
System.out.print(": ");
System.out.println(e);
}
}
输出:
位置#43:(1; 11)
地址#1:英国伦敦
雇主#11:S先生