我正在尝试使用google gson TypeAdapter将嵌套的JSON转换为嵌套的Java对象,并为每个类实现TypeAdapter。但我不想在单个适配器类中编写完整的read()方法逻辑。我在网上提到了一些问题和blog例子。但是完整的读逻辑是单一的。
对于小型嵌套对象,可以在单个适配器中使用逻辑,但对于大对象(每个类中有超过10-15个字段),它并不好。
[更新]
例如,json键看起来与类属性相同,但实际上我将以hyphen-separated-small-case
键而不是Camel case
键获得输入。所以我的json和java类属性名称将不相同,因此我必须编写我的自定义逻辑进行映射。
E.g。 示例Json输入:
{
"id": 1,
"name": "Alex",
"emailId": "alex@gmail.com",
"address": {
"address": "21ST & FAIRVIEW AVE",
"district": "district",
"city": "EATON",
"region": "PA",
"postalCode": "18044",
"country": "US"
}
}
Java bean如下:
//Employee object class
public class Employee {
private int id;
private String name;
private String emailId;
private Address address;
..
}
//Address object class
public class Address {
private String address;
private String district;
private String city;
private String region;
private String postalCode;
private String country;
..
}
我希望有两个不同的适配器,并在read()方法中集成多个适配器。
public class EmployeeAdapter extends TypeAdapter<Employee> {
@Override
public void write(JsonWriter out, Employee employee) throws IOException {
//
}
@Override
public Employee read(JsonReader jsonReader) throws IOException {
//read logic for employee class using AddressAdapter for address json
}
}
public class AddressAdapter extends TypeAdapter<Address> {
@Override
public void write(JsonWriter out, Address address) throws IOException {
//
}
@Override
public Address read(JsonReader jsonReader) throws IOException {
//read logic for Address class
}
}
如何在EmployeeAdapter中使用AddressAdapter?
答案 0 :(得分:3)
我遇到了同样的问题,为我找到了合适的解决方案。
您可以借助TypeAdapter<T>
对象及其方法Gson
获取新的getAdapter(Class<T> type)
实例。
因此,您提供的示例如下所示:
Java Beans:
//Employee object class
@JsonAdapter(EmployeeAdapter.class)
public class Employee {
private int id;
private String name;
private String emailId;
private Address address;
..
}
//Address object class
@JsonAdapter(AddressAdapter.class)
public class Address {
private String address;
private String district;
private String city;
private String region;
private String postalCode;
private String country;
..
}
类型适配器:
public class EmployeeAdapter extends TypeAdapter<Employee> {
@Override
public void write(JsonWriter out, Employee employee) throws IOException {
//
}
@Override
public Employee read(JsonReader jsonReader) throws IOException {
Employee employee = new Employee();
jsonReader.beginObject();
//read your Employee fields
TypeAdapter<Address> addressAdapter = new Gson().getAdapter(Address.class);
employee.setAddress(addressAdapter.read(jsonReader);
return employee;
}
}
public class AddressAdapter extends TypeAdapter<Address> {
@Override
public void write(JsonWriter out, Address address) throws IOException {
//
}
@Override
public Address read(JsonReader jsonReader) throws IOException {
Address address = new Address();
//read your Address fields
return address;
}
}
使用此解决方案,您可以获得松散耦合的代码,因为Bean JsonAdapter
注释中只有依赖项。
Addtional您将每个Bean的读/写逻辑拆分为它自己的TypeAdapter。
答案 1 :(得分:2)
我将TypeAdapterFactory用于此类事情。它允许将gson实例传递给TypeAdapter实例。
(在下面的示例中,我将“ rawType”传递给TypeAdapter实例,因为它通常很有用。如果不需要,可以将其取出。)
示例TypeAdapterFactory:
public class ContactTypeAdapterFactory implements TypeAdapterFactory {
// Add @SuppressWarnings("unchecked") as needed.
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
final Class<? super T> rawClass = typeToken.getRawType();
if (Employee.class.isAssignableFrom(rawClass)) {
// Return EmployeeAdapter for Employee class
return EmployeeAdapter.get(rawClass, gson);
}
if (Address.class.isAssignableFrom(rawClass)) {
// Return AddressAdapter for Address class
return AddressAdapter.get(rawClass, gson);
}
return null; // let Gson find somebody else
}
private static final class EmployeeAdapter<T> extends TypeAdapter<T> {
private final Gson gson;
private final Class<? super T> rawClass; // Not used in this example
private EmployeeAdapter(Class<? super T> rawClass, Gson gson) {
this.rawClass = rawClass;
this.gson = gson;
}
private static <T> TypeAdapter<T> get(Class<? super T> rawClass, Gson gson) {
// Wrap TypeAdapter in nullSafe so we don't need to do null checks
return new EmployeeAdapter<>(rawClass, gson).nullSafe();
}
@Override
public void write(JsonWriter out, T value)
throws IOException {
// We should only ever be here for Employee types
// Cast value to Employee
Employee record = (Employee)value;
// Output start of JSON object
out.beginObject();
// Output key / value pairs
out.name("name");
gson.getAdapter(String.class).write(out, record.getName());
// [...]
out.name("address");
gson.getAdapter(Address.class).write(out, record.getAddress());
// Output end of JSON object
out.endObject();
}
@Override
public T read(JsonReader in)
throws IOException {
String fieldName;
// Create an empty Employee object
Employee record = new Employee();
// Consume start of JSON object
in.beginObject();
// Iterate each key/value pair in the json object
while (in.hasNext()) {
fieldName = in.nextName();
switch (fieldName) {
case "name":
record.setName(gson.getAdapter(String.class).read(in));
break;
// [...]
case "address":
record.setAddress(gson.getAdapter(Address.class).read(in));
break;
default:
// Skip any values we don't support
in.skipValue();
}
}
// Consume end of JSON object
in.endObject();
// Return new Object
return (T)record;
}
}
private static final class AddressAdapter<T> extends TypeAdapter<T> {
private final Gson gson;
private final Class<? super T> rawClass; // Not used in this example
private AddressAdapter(Class<? super T> rawClass, Gson gson) {
this.rawClass = rawClass;
this.gson = gson;
}
private static <T> TypeAdapter<T> get(Class<? super T> rawClass, Gson gson) {
// Wrap TypeAdapter in nullSafe so we don't need to do null checks
return new AddressAdapter<>(rawClass, gson).nullSafe();
}
@Override
public void write(JsonWriter out, T value)
throws IOException {
// We should only ever be here for Address types
// Cast value to Address
Address record = (Address)value;
// Output start of JSON object
out.beginObject();
// Output key / value pairs
out.name("address");
gson.getAdapter(String.class).write(out, record.getName());
// [...]
out.name("country");
gson.getAdapter(String.class).write(out, record.getCountry());
// Output end of JSON object
out.endObject();
}
@Override
public T read(JsonReader in)
throws IOException {
String fieldName;
Address record = new Address();
in.beginObject();
// Iterate each parameter in the json object
while (in.hasNext()) {
fieldName = in.nextName();
switch (fieldName) {
case "address":
record.setAddress(gson.getAdapter(String.class).read(in));
break;
// [...]
case "country":
record.setCountry(gson.getAdapter(String.class).read(in));
break;
default:
in.skipValue();
}
}
in.endObject();
return (T)record;
}
}
}
使用:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new ContactTypeAdapterFactory())
.create();
Employee employee = gson.fromJson(jsonString, Employee.class);
答案 2 :(得分:0)
您可以创建AddressAdapter
封装在EmployeeAdapter
中的新实例。请仔细阅读以下示例。
public class EmployeeAdapter extends TypeAdapter<Employee> {
//private instance of address adapter
private AddressAdapter addressAdapter = new AddressAdapter();
@Override
public void write(JsonWriter out, Employee employee) throws IOException {
//TODO: do your stuff to Employee class
//manually do it to Address class
addressAdapter.write(out, employee.getAddress());
}
@Override
public Employee read(JsonReader jsonReader) throws IOException {
//your new instance of employee
Employee employee = new Employee();
//TODO: read logic for employee class using AddressAdapter for address json
//read from Address class
Address address = addressAdapter.read(jsonReader);//you may need only portion of address available, simply grab that string as same as other properties if needed
employee.setAddress(address);
}
}