对于声明期间初始化的最终变量,Jackson是否正确运行? - java

考虑以下针对Jackson 2.9.5的(失败)JUnit测试:

package de.azamir.test;

import static org.junit.Assert.assertEquals;

import java.io.IOException;

import org.junit.Test;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonFinalTest {

    private static final class MyClass {

        @JsonProperty("myProperty")
        public final String myProperty = "myPropertyValueInit";
    }

    @Test
    public void doTest() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, JsonParseException, JsonMappingException, IOException {

        final MyClass deserializedMyClass1 = new ObjectMapper().readValue("{\"myProperty\":\"myPropertyValueDeserialized\"}", MyClass.class);

        // "myPropertyValueInit"
        final String directValue = deserializedMyClass1.myProperty;

        // "myPropertyValueDeserialized"
        final String reflectValue = (String) MyClass.class.getDeclaredField("myProperty").get(deserializedMyClass1);

        assertEquals(directValue, reflectValue);

    }
}

我怀疑Java VM会优化对最终字段的访问,以使Jackson的值(通过反射)只能通过反射再次检索。直到今天,这在我们的代码库中导致了非常微妙且难以发现的错误。

这是杰克逊以某种方式解决的一个问题吗?我的直觉是,Jackson代码无法“看到”此信息,但谁知道。

我知道有多种方法可以改进此代码,例如

删除@JsonProperty并禁用final字段作为mutator
不是在声明期间初始化字段,而是在构造函数中
根本没有使字段最终确定

但是有没有推荐的方法来确保我们团队中没有开发人员(谁可能不知道这一警告)呢?

参考方案

因此,有一种方法:(来自this answer的想法,也很容易理解this question)而不是使用constant expression并直接在声明站点分配变量,而是在构造函数中初始化最终变量。使用MyClass2时查看更改:

public class JacksonFinalTest {

    private static final class MyClass {

        @JsonProperty("myProperty")
        public final String myProperty = "myPropertyValueInit";
    }

    private static final class MyClass2 {

        @JsonProperty("myProperty")
        public final String myProperty;

        public MyClass2() {
            myProperty = "myPropertyValueInit";
        }
    }

    @Test
    public void doTest() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, JsonParseException, JsonMappingException, IOException {

        final String json = "{\"myProperty\":\"myPropertyValueDeserialized\"}";
        final MyClass2 deserializedMyClass1 = new ObjectMapper().readValue(json, MyClass2.class);

        // "myPropertyValueInit"
        final String directValue = deserializedMyClass1.myProperty;

        // "myPropertyValueDeserialized"
        final String reflectValue = (String) MyClass2.class.getDeclaredField("myProperty").get(deserializedMyClass1);

        assertEquals(directValue, reflectValue);

    }
}

Java-搜索字符串数组中的字符串 - java

在Java中,我们是否有任何方法可以发现特定字符串是字符串数组的一部分。我可以避免出现一个循环。例如String [] array = {"AA","BB","CC" }; string x = "BB" 我想要一个if (some condition to tell wheth…

Jackson:使用不同的属性名称序列化/反序列化 - java

我有这个POJO:public class SetPoint { private String tagName; //more fields //getters and setters } 我从REST API获取SetPoints,对它们进行处理,然后再次发送。问题是我想从JSON反序列化SetPoint,例如:{ "tagnameOpc…

Java RegEx中的单词边界\ b - java

我在使用\b作为Java Regex中的单词定界符时遇到困难。对于text = "/* sql statement */ INSERT INTO someTable"; Pattern.compile("(?i)\binsert\b");找不到匹配项Pattern insPtrn = Pattern.compile(&…

Java Double与BigDecimal - java

我正在查看一些使用双精度变量来存储(360-359.9998779296875)结果为0.0001220703125的代码。 double变量将其存储为-1.220703125E-4。当我使用BigDecimal时,其存储为0.0001220703125。为什么将它双重存储为-1.220703125E-4? 参考方案 我不会在这里提及精度问题,而只会提及数字…

Java:线程池如何将线程映射到可运行对象 - java

试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …