Java Jackson反序列化绕过了final字段

Java Jackson反序列化绕过了final字段,java,json,jackson,immutability,lombok,Java,Json,Jackson,Immutability,Lombok,这是密码 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 { Fiel

这是密码

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注释构造函数?(从字段中删除@JsonProperty会导致错误;我甚至不需要使用正确的属性进行注释)
多谢各位

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

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

public Fields() {
    this.value1 = 0;
    this.value2 = 0;
    System.out.println("cons: " + this);
}
(这必须初始化字段,因为它们是
final
)或者您可以拥有一个构造函数,Jackson将根据声明的
@JsonProperty
名称尝试解析该构造函数。请注意,
JsonProperty#required
默认为
false

为什么jackson修改了没有setter的私有final字段 在完成建造之后?如果这是有意的,我如何扭转它 走开

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

为什么jackson在完成构建后修改了没有setter的私有final字段?如果这是有意的,我如何关闭它

您可以在配置映射器时将
MapperFeature.ALLOW\u FINAL\u FIELDS\u AS\u 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}

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