java 杰克逊反序列化绕过最终领域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30340946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:56:51  来源:igfitidea点击:

Hymanson deserialization circumventing final fields

javajsonHymansonimmutabilitylombok

提问by surasak

Here's the code

这是代码

import com.fasterxml.Hymanson.annotation.JsonProperty;
import com.fasterxml.Hymanson.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);
        }
    }
}

Output

输出

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)

My questions are:

我的问题是:

  • Why did Hymanson modify private final fields that do not have setters after finish constructing it? If this is intended, how do I turn it off?
  • If Hymanson is able to set fields directly, why is it required that I annotate the constructor with @JsonProperty? (Removing @JsonProperty from Fields results in error; and I didn't even need to annotate with correct properties)
  • 为什么Hymanson在构建完成后修改没有setter的私有final字段?如果这是有意的,我该如何关闭它?
  • 如果 Hymanson 能够直接设置字段,为什么需要我用 @JsonProperty 注释构造函数?(从字段中删除 @JsonProperty 会导致错误;我什至不需要使用正确的属性进行注释)

Thank you

谢谢

回答by Sotirios Delimanolis

Why is it required that I annotate the constructor with @JsonProperty?

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

It's not. What is required is an accessible constructor. You can either have a parameterless constructor

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

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

(that necessarily initializes the fields since they are final) or you can have a constructor that Hymanson will try to resolve based on the declared @JsonPropertyname. Note that JsonProperty#requiredis falseby default.

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

Why did Hymanson modify private final fields that do not have setters after finish constructing it? If this is intended, how do I turn it off?

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

Because it can. It thus allows you to use immutable types with deserialization. There is no built-in way that I know of through which you can disable this feature.

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

回答by Oleksandr Matiash

Why did Hymanson modify private final fields that do not have setters after finish constructing it? If this is intended, how do I turn it off?

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

You can set MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORSproperty to false(it is trueby default) when configuring your mapper.

您可以在配置映射器时将MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS属性设置为falsetrue默认情况下)。

Example:

例子:

import com.fasterxml.Hymanson.annotation.JsonCreator;
import com.fasterxml.Hymanson.annotation.JsonProperty;
import com.fasterxml.Hymanson.databind.DeserializationFeature;
import com.fasterxml.Hymanson.databind.MapperFeature;
import com.fasterxml.Hymanson.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 + '}';
    }
}

}

}

Output:

输出:

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