Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.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
Java Jackson,使用私有字段反序列化类,使用无注释的arg构造函数_Java_Json_Jackson_Jackson2_Jackson Databind - Fatal编程技术网

Java Jackson,使用私有字段反序列化类,使用无注释的arg构造函数

Java Jackson,使用私有字段反序列化类,使用无注释的arg构造函数,java,json,jackson,jackson2,jackson-databind,Java,Json,Jackson,Jackson2,Jackson Databind,可以反序列化到具有私有字段和自定义参数构造函数的类,而无需使用注释,也无需使用Jackson 我知道在Jackson中使用这种组合是可能的:1)Java8,2)使用“-parameters”选项编译,3)参数名称匹配JSON。但默认情况下,在GSON中也可以不受所有这些限制 例如: public class Person { private final String firstName; private final String lastName; private fin

可以反序列化到具有私有字段和自定义参数构造函数的类,而无需使用注释,也无需使用Jackson

我知道在Jackson中使用这种组合是可能的:1)Java8,2)使用“-parameters”选项编译,3)参数名称匹配JSON。但默认情况下,在GSON中也可以不受所有这些限制

例如:

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public static void main(String[] args) throws IOException {
        String json = "{firstName: \"Foo\", lastName: \"Bar\", age: 30}";
        
        System.out.println("GSON: " + deserializeGson(json)); // works fine
        System.out.println("Jackson: " + deserializeJackson(json)); // error
    }

    public static Person deserializeJackson(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        return mapper.readValue(json, Person.class);
    }

    public static Person deserializeGson(String json) {
        Gson gson = new GsonBuilder().create();
        return gson.fromJson(json, Person.class);
    }
}
这对GSON来说很好,但Jackson提出:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `jacksonParametersTest.Person` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{firstName: "Foo", lastName: "Bar", age: 30}"; line: 1, column: 2]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
这在GSON中是可能的,因此我认为Jackson中一定有某种方法,不需要修改Person类,不需要java8,也不需要显式的自定义反序列化器。有人知道解决办法吗

  • 更新,其他信息

Gson似乎跳过了参数构造函数,因此它必须在幕后使用反射创建一个无参数构造函数

此外,存在一个可以对Kotlin数据类执行此操作的编译器,即使没有“-parameters”编译器标志。 所以很奇怪,对于javajackson来说,这样的解决方案似乎并不存在

这是Kotlin Jackson中提供的(漂亮且干净的)解决方案(IMO也应通过自定义模块在Java Jackson中提供该解决方案):


由于没有默认构造函数,jackson或gson希望自己创建实例。您应该告诉API如何通过提供 自定义反序列化

下面是一段代码

public class PersonDeserializer extends StdDeserializer<Person> { 
    public PersonDeserializer() {
        super(Person.class);
    } 

    @Override
    public Person deserialize(JsonParser jp, DeserializationContext ctxt) 
            throws IOException, JsonProcessingException {
        try {
            final JsonNode node = jp.getCodec().readTree(jp);
            final ObjectMapper mapper = new ObjectMapper();
            final Person person = (Person) mapper.readValue(node.toString(),
                    Person.class);
            return person;
        } catch (final Exception e) {
            throw new IOException(e);
        }
    }
}

Jackson提供了解决您问题的模块

您必须按照以下方式构建
ObjectMapper

ObjectMapper mapper = new ObjectMapper()
        .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
        .registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES));
您必须添加
-参数
作为编译器参数

maven的示例:

 <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <version>3.5.1</version>
       <configuration>
           <!--somecode-->

           <compilerArgument>-parameters</compilerArgument>

       </configuration>
 </plugin>

org.apache.maven.plugins
maven编译器插件
3.5.1
-参数
对于gradle:

compileJava {
  options.compilerArgs << "-parameters"
}
compileJava{
options.compilerArgs解决方案,带混合注释
您可以使用混合注释。当不需要修改类时,这是一个很好的选择。您可以将其视为一种面向方面的方式,在运行时添加更多注释,以增强静态定义的注释

假设您的
Person
类定义如下:

公共类人物{
私有最终字符串名;
私有最终字符串lastName;
私人最终年龄;
公众人物(字符串名、字符串名、整数){
this.firstName=firstName;
this.lastName=lastName;
这个。年龄=年龄;
}
//消除剂
}
首先在注释抽象类中定义一个混合:

公共抽象类PersonMixIn{
PersonMixIn(@JsonProperty(“firstName”)字符串firstName,
@JsonProperty(“lastName”)字符串lastName,
@JsonProperty(“年龄”)int(年龄){
}
}
然后配置
ObjectMapper
以将定义的类用作POJO的混合:

ObjectMapper mapper=new ObjectMapper();
enable(JsonParser.Feature.ALLOW\u UNQUOTED\u FIELD\u name);
addMixIn(Person.class,PersonMixIn.class);
并反序列化JSON:

String json=“{firstName:\'Foo\',lastName:\'Bar\',年龄:30}”;
Person=mapper.readValue(json,Person.class);

只有在您可以更改类实现的情况下,下面的解决方案才有效

一个简单的解决方案就是创建一个默认构造函数

Person()
Person
类中

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

    public Person() {
    }

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    ...
}

person
创建一个空构造函数,但这需要修改类。我的问题是,在不修改它的情况下,是否可以这样做,就像使用Gson一样。(我将在问题中更明确地说明这一点。)因此,您不想注释类,不想使用参数名称解决方案,也不想使用自定义反序列化程序。在我尝试编写答案之前,还需要做些什么吗?不太需要,我也没有为问题添加新的要求。基本上情况是:您的代码库之外有大量不可变的类,如何o在没有样板代码的情况下高效地反序列化它们。解决方案可能在于一个尚未存在的自定义Jackson模块,或者使用“-parameter”标志。(此标志很麻烦,因为1)它需要重新编译,2)IntelliJ忽略Maven编译器标志。但我已接受Kotlin Jackson模块作为我项目的解决方案。@Kalaiselvan,我对你的评论投了赞成票,因为它对我的同事有效。但我没有提供默认/空构造函数,我仍然能够计算出来。唯一的区别是我使用的是windows 10和他使用了Mac。代码在
Person=(Person)mapper.readValue(node.toString(),Person.class)处给出了一个错误;
无法构造“jacksonParametersTest.Person”的实例。
这也是一个自定义反序列化程序解决方案,而我正在寻找一个没有的。默认情况下,Gson可以做到。Jackson的Kotlin模块也可以做到:。我还发现Gson跳过了参数构造函数,所以它正在创建一个默认的无参数构造函数在幕后。OP已经提到了这个选项并且不想要它,可能他们没有运行Java 8。@user1803551他提到了Kotlin类的这个选项。@user1803551他说“很奇怪,Java Jackson似乎不存在这样的解决方案。”在我看来,他搜索这个解决方案。如果你不想创建自定义反序列化程序,Jackson不支持另一种解决问题的方法。他说,“所以我认为Jackson中一定有某种方法,不需要修改Person类,不需要Java 8,也不需要显式自定义反序列化程序。有人知道解决方案吗?”您的解决方案需要Java 8。@Devabc我知道,当您使用“-parameters”时,您必须通过
mvn compile
编译类,如果您的类在外部,则必须创建自定义的
反序列化程序
mixincompileJava {
  options.compilerArgs << "-parameters"
}
public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

    public Person() {
    }

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    ...
}