Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用gson TypeAdapter将嵌套JSON转换为嵌套Java对象_Java_Json_Gson_Json Deserialization - Fatal编程技术网

使用gson TypeAdapter将嵌套JSON转换为嵌套Java对象

使用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类属性

我试图使用GoogleGSON将嵌套的JSON转换成嵌套的Java对象,每个类都有TypeAdapter的实现。但我不想在单个适配器类中编写完整的read()方法逻辑。我在网上提到了一些问题和例子。但完整的读取逻辑在单个类中

对于小型嵌套对象,在单个适配器中具有逻辑是很好的,但对于大型对象(每个类中有10-15个以上的字段)则不是很好

[更新]

例如,json键看起来与of class属性相同,但实际上,我将以
连字符分隔的小写键而不是
驼峰大小写
键的形式获取输入。因此,我的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{
地址=新地址();
//读取您的地址字段
回信地址;
}
}
使用此解决方案,您可以获得松散耦合代码的好处,因为bean
JsonAdapter
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);