Jackson 反序列化绕过最终字段

问题描述 投票:0回答:2

这是代码

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 在构建完成后要修改没有 setter 的私有 Final 字段?如果这是有意的,我该如何将其关闭?
  • 如果jackson可以直接设置字段,为什么需要我在构造函数上添加@JsonProperty注释? (从 Fields 中删除 @JsonProperty 会导致错误;而且我什至不需要使用正确的属性进行注释)

谢谢你

java json jackson immutability lombok
2个回答
16
投票

为什么 Jackson 在构建完成后要修改没有 setter 的私有 Final 字段?如果这是有意的,我该如何将其关闭?

您可以在配置映射器时将

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}

14
投票

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

不是的。所需要的是一个可访问的构造函数。您可以使用无参数构造函数

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

(必须初始化字段,因为它们是

final
)或者您可以拥有一个构造函数,Jackson 将尝试根据声明的
@JsonProperty
名称来解析该构造函数。请注意,默认情况下,
JsonProperty#required
false

为什么 Jackson 修改了没有 setter 的私有 Final 字段 建造完成后?如果这是有意的,我该如何转动它 关闭?

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

© www.soinside.com 2019 - 2024. All rights reserved.