Gov*_*ndS 5 java json gson json-deserialization
我正在尝试使用 google gson TypeAdapter将嵌套 JSON 转换为嵌套 Java 对象,并为每个类实现 TypeAdapter 。但我不想在单个适配器类中编写完整的 read() 方法逻辑。我在网上提到了一些问题和博客示例。但完整的读取逻辑位于单个类中。
对于小型嵌套对象,在单个适配器中包含逻辑是可以的,但对于大型对象(每个类中有超过 10-15 个字段)则不好。
[更新]
例如,json 键看起来与类属性相同,但实际上我将获取输入作为hyphen-separated-small-case键而不是Camel case键。所以我的 json 和 java 类属性名称不会相同,因此我必须编写自定义映射逻辑。
例如示例 Json 输入:
{
"id": 1,
"name": "Alex",
"emailId": "alex@gmail.com",
"address": {
"address": "21ST & FAIRVIEW AVE",
"district": "district",
"city": "EATON",
"region": "PA",
"postalCode": "18044",
"country": "US"
}
}
Run Code Online (Sandbox Code Playgroud)
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;
..
}
Run Code Online (Sandbox Code Playgroud)
我想要有两个不同的适配器并在 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
}
}
Run Code Online (Sandbox Code Playgroud)
如何在 EmployeeAdapter 中使用 AddressAdapter?
我使用 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new ContactTypeAdapterFactory())
.create();
Employee employee = gson.fromJson(jsonString, Employee.class);
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5186 次 |
| 最近记录: |