【问题标题】:Jackson deserialization circumventing final fields杰克逊反序列化绕过最终字段
【发布时间】:2015-08-01 04:27:12
【问题描述】:

这是代码

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.ToString;

public class Main {
    public static void main(String[] args) throws Exception {
        Fields f1 = new Fields(1);
        System.out.println(f1);

        ObjectMapper mapper = new ObjectMapper();
        String str = mapper.writeValueAsString(f1);
        System.out.println(str);

        Fields f2 = mapper.readValue(str, Fields.class);
        System.out.println(f2);
    }

    @Data
    @ToString
    public static class Fields {
        private final long value1;
        private final long value2;

        public Fields(@JsonProperty("blah") long value) {
            this.value1 = value++;
            this.value2 = value++;
            System.out.println(this);
        }
    }
}

输出

Main.Fields(value1=1, value2=2)
Main.Fields(value1=1, value2=2)
{"value1":1,"value2":2}
Main.Fields(value1=0, value2=1)
Main.Fields(value1=1, value2=2)

我的问题是:

  • 为什么杰克逊在完成构建后修改了没有设置器的私有最终字段?如果这是有意的,我该如何关闭它?
  • 如果jackson能够直接设置字段,为什么我需要用@JsonProperty注释构造函数? (从 Fields 中删除 @JsonProperty 会导致错误;我什至不需要使用正确的属性进行注释)

谢谢

【问题讨论】:

    标签: java json jackson immutability lombok


    【解决方案1】:

    为什么需要我用@JsonProperty 注释构造函数?

    不是。需要的是一个可访问的构造函数。你可以有一个无参数的构造函数

    public Fields() {
        this.value1 = 0;
        this.value2 = 0;
        System.out.println("cons: " + this);
    }
    

    (必须初始化字段,因为它们是final)或者您可以拥有一个构造函数,Jackson 将尝试根据声明的 @JsonProperty 名称解析。注意JsonProperty#required默认是false

    杰克逊为什么要修改没有设置器的私有最终字段 建成后呢?如果这是有意的,我该如何打开它 关了吗?

    因为它可以。因此,它允许您使用带有反序列化的不可变类型。据我所知,没有内置方法可以禁用此功能。

    【讨论】:

    • “因为它可以。” - 这让我笑了。
    • 但是 ObjectMapper 是如何修改最终字段的,或者使用什么底层机制?我知道它使用反射,但它是否以某种方式使该字段非最终并设置它?
    • 当然,如果存在带注释的构造函数,那么杰克逊不应该修改字段吗?它应该是其中之一。
    • @mjaggard 我目前无法验证这一点,但我假设 Jackson 尝试分配 JSON 中的每个属性,无论是通过构造函数还是通过 mutators(设置器或字段)。
    【解决方案2】:

    为什么杰克逊在完成构建后修改了没有设置器的私有最终字段?如果这是有意的,我该如何关闭它?

    您可以在配置映射器时将MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS 属性设置为false(默认为true)。

    例子:

    import com.fasterxml.jackson.annotation.JsonCreator;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.MapperFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class Temp {
    
    private static final String RAW = "{\"value1\": \"aabbcc\",\"value2\":\"zzzzz\"}";
    
    public static void main(String[] args) throws Exception {
        System.out.println(new ObjectMapper().readValue(RAW, TestClass.class));
    
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // you will receive UnrecognizedPropertyException without this line
        mapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, false);
    
        System.out.println(mapper.readValue(RAW, TestClass.class));
    }
    
    public static class TestClass {
    
        private final String value1;
        private final String value2;
    
        @JsonCreator
        public static TestClass createTestClass(
                @JsonProperty("value1") String value1,
                @JsonProperty("blah") String value2) {
    
            return new TestClass(value1, value2);
        }
    
        private TestClass(String value1, String value2) {
            this.value1 = value1;
            this.value2 = value2;
        }
    
        public String getValue1() {
            return value1;
        }
    
        public String getValue2() {
            return value2;
        }
    
        @Override
        public String toString() {
            return "TestClass{" + "value1=" + value1 + ", value2=" + value2 + '}';
        }
    }
    

    }

    输出:

    TestClass{value1=aabbcc, value2=zzzzz}
    TestClass{value1=aabbcc, value2=null}
    

    【讨论】:

      猜你喜欢
      • 2013-07-10
      • 1970-01-01
      • 1970-01-01
      • 2013-02-23
      • 2015-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-19
      相关资源
      最近更新 更多