使用gson TypeAdapter将嵌套JSON转换为嵌套Java对象
我试图使用GoogleGSON将嵌套的JSON转换成嵌套的Java对象,每个类都有TypeAdapter的实现。但我不想在单个适配器类中编写完整的read()方法逻辑。我在网上提到了一些问题和例子。但完整的读取逻辑在单个类中 对于小型嵌套对象,在单个适配器中具有逻辑是很好的,但对于大型对象(每个类中有10-15个以上的字段)则不是很好 [更新] 例如,json键看起来与of class属性相同,但实际上,我将以使用gson TypeAdapter将嵌套JSON转换为嵌套Java对象,java,json,gson,json-deserialization,Java,Json,Gson,Json Deserialization,我试图使用GoogleGSON将嵌套的JSON转换成嵌套的Java对象,每个类都有TypeAdapter的实现。但我不想在单个适配器类中编写完整的read()方法逻辑。我在网上提到了一些问题和例子。但完整的读取逻辑在单个类中 对于小型嵌套对象,在单个适配器中具有逻辑是很好的,但对于大型对象(每个类中有10-15个以上的字段)则不是很好 [更新] 例如,json键看起来与of class属性相同,但实际上,我将以连字符分隔的小写键而不是驼峰大小写键的形式获取输入。因此,我的json和java类属性
连字符分隔的小写键而不是驼峰大小写
键的形式获取输入。因此,我的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"
}
}
和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()方法中集成多个适配器
公共类EmployeeAdapter扩展了TypeAdapter{
@凌驾
public void write(JsonWriter out,Employee-Employee)抛出IOException{
//
}
@凌驾
公共雇员读取(JsonReader JsonReader)引发IOException{
//使用AddressAdapter for address json读取employee类的逻辑
}
}
公共类AddressAdapter扩展了TypeAdapter{
@凌驾
public void write(JsonWriter out,Address Address)引发IOException{
//
}
@凌驾
公共地址读取(JsonReader JsonReader)引发IOException{
//读取地址类的逻辑
}
}
如何在EmployeeAdapter中使用AddressAdapter 您可以创建封装在EmployeeAdapter
中的AddressAdapter
的新实例。请看下面的例子
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);
}
}
公共类EmployeeAdapter扩展了TypeAdapter{
//地址适配器的私有实例
private AddressAdapter AddressAdapter=新的AddressAdapter();
@凌驾
public void write(JsonWriter out,Employee-Employee)抛出IOException{
//TODO:对员工课做你的事情
//手动执行此操作以寻址类
addressAdapter.write(out,employee.getAddress());
}
@凌驾
公共雇员读取(JsonReader JsonReader)引发IOException{
//您的新员工实例
员工=新员工();
//TODO:使用AddressAdapter为AddressJSON读取employee类的逻辑
//从地址类读取
Address Address=addressAdapter.read(jsonReader);//您可能只需要可用地址的一部分,如果需要,只需获取与其他属性相同的字符串即可
employee.setAddress(地址);
}
}
我也遇到了同样的问题,并找到了适合我的解决方案
您可以通过Gson
对象及其方法getAdapter(类类型)
获得一个新的TypeAdapter
实例
因此,您提供的示例如下所示:
Java bean:
//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;
}
}
公共类EmployeeAdapter扩展了TypeAdapter{
@凌驾
public void write(JsonWriter out,Employee-Employee)抛出IOException{
//
}
@凌驾
公共雇员读取(JsonReader JsonReader)引发IOException{
员工=新员工();
jsonReader.beginObject();
//读取您的员工字段
TypeAdapter addressAdapter=new Gson().getAdapter(Address.class);
employee.setAddress(addressAdapter.read,jsonReader);
返回员工;
}
}
公共类AddressAdapter扩展了TypeAdapter{
@凌驾
public void write(JsonWriter out,Address Address)引发IOException{
//
}
@凌驾
公共地址读取(JsonReader JsonReader)引发IOException{
地址=新地址();
//读取您的地址字段
回信地址;
}
}
使用此解决方案,您可以获得松散耦合代码的好处,因为beanJsonAdapter
annotation中只有依赖项。
另外,您将每个Bean的读/写逻辑拆分为它自己的TypeAdapter。我使用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;
}
}
}
您是否尝试过使用读卡器的默认实现?或者您有编写自己的适配器的具体原因吗?这与Jackson有什么关系?请删除标记看起来您只需要POJO映射,而类型适配器在这里真的是一个过火的工具:final Employee Employee=gson.fromJson(…,Employee.class)似乎是完整的。@ LuByyrrHaydAdRiv:更新的问题。谢谢你把它弄清楚。@斯蒂芬林德纳:是的,例如,我只将样本JSON复制为类属性,但是我必须在实际中考虑连字符分隔的小写属性名称。这就是为什么我需要编写自定义的一个。这是可以的。但是将没有使用扩展。AddressAdapter中的TypeAdapter
。在每个EmployeeAdapter#read()
调用上创建新的Gson
对象,我认为这不好,因为Gson
构造函数非常重。除了Varvara关于为每个读取调用创建新的Gson实例的性能影响的观点之外,“TypeAdapter addressAdapter=new Gson().getAdapter(Address.class)”将不起作用,因为addressAdapter尚未在您正在创建的新Gson实例中注册。
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);