Jackson 可以自动将任何构造函数参数视为 JsonProperty 吗?

Posted

技术标签:

【中文标题】Jackson 可以自动将任何构造函数参数视为 JsonProperty 吗?【英文标题】:Can Jackson automatically treat any constructor parameter as a JsonProperty? 【发布时间】:2022-01-13 20:54:19 【问题描述】:

如何让 Jackson 将“名称”视为具有 @JsonProperty 注释?

public class SimpleClass 
    private String name;
    private String doNotSerialize;

    public SimpleClass( @JsonProperty("name") String name ) 
        this.name = name;
    

    public String getName() 
        return name;
    
    
    public int getSum() 
        return 1+1;
    

现在的情况,我收到一个错误,无法识别字段“sum”,因为它将每个 getter 都视为可序列化的属性。

如果我添加一个类注释:

@JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE )

序列化时我得到一个空字符串。我希望 Jackson 会在构造函数参数上看到 @JsonProperty 并弄清楚。

如果我将类注释更改为:

@JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.ANY )

然后我得到包含的“doNotSerialize”字段。

如果我在构造函数上设置@JsonCreator,并更改我的自动检测,我仍然会得到一个空白字符串:

@JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY )
public class SimpleClass 
    private String name;
    private String doNotSerialize;

    @JsonCreator
    public SimpleClass( @JsonProperty("name") String name ) 
        this.name = name;
    

    public String getName() 
        return name;
    
    
    public int getSum() 
        return 1+1;
    

我希望以某种方式告诉 Jackson 将所有构造函数参数视为可序列化字段,而将所有其他字段/设置器视为不可序列化。

【问题讨论】:

你在getSum上试过@JsonIgnore吗? 我知道这行得通,但在我的实际项目中,我有数百个类,每个类都有未知数量的 getXXX 方法,我不想序列化。如果我添加 getXXX() 而不记得添加 @JsonIgnore,它将在运行时中断,因为当我尝试反序列化时,会抛出错误,因为构造函数中没有“sum”属性。我试图避免创建一个可能在运行时失败的编程陷阱。 您是否考虑过拥有 SimpleClass(仅限数据)和 SimpleClassWrapper(派生的 getter,例如 getSum(),在其构造函数中采用 SimpleClass)。这样你就可以在你的代码中使用 SimpleClass 进行序列化和 SimpleClassWrapper 来简化/重用你的派生 getter 的代码。 【参考方案1】:

您可以使用过滤器仅序列化具有匹配字段的 getter,例如

package org.example;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;

import java.io.IOException;
import java.io.StringWriter;


public class App 
    @JsonFilter("test")
    public static class SimpleClass 
        private String name;
        private String doNotSerialize;

        public SimpleClass(String name ) 
            this.name = name;
        

        public String getName() 
            return name;
        

        public int getSum() 
            return 1+1;
        
    
    public static void main( String[] args ) throws IOException 
        SimpleFilterProvider filterProvider = new SimpleFilterProvider();
        filterProvider.addFilter("test", new SimpleBeanPropertyFilter() 
            @Override
            protected boolean include(BeanPropertyWriter writer) 
                return super.include(writer);
            

            @Override
            protected boolean include(PropertyWriter writer) 
                String name = writer.getName();
                Class clazz = writer.getMember().getDeclaringClass();
                try 
                    clazz.getDeclaredField(name);
                    return super.include(writer);
                 catch (NoSuchFieldException e) 
                    // ignore
                    return false;
                
            
        );
        ObjectMapper mapper = new ObjectMapper();
        mapper.setFilterProvider(filterProvider);
        StringWriter sw = new StringWriter();
        mapper.createGenerator(sw).writeObject(new SimpleClass("foo"));
        System.out.println(sw.toString());
    

我不知道您的全部要求,但这应该是一个开始。

我并没有尝试做你实际询问的事情,即查看构造函数参数,但这也应该是可能的。

【讨论】:

【参考方案2】:

如果您希望“sum”包含在 serializad json 中,但想在反序列化时忽略它,您可以这样做:

@JsonIgnoreProperties(ignoreUnknown=true)
public class SimpleClass  
   // properties/getters 

   public int getSum()  return 1+1; 

如果你想完全从 json 中删除“sum”,你可以这样做

@JsonIgnoreProperties("sum")
public class SimpleClass  
   // properties/getters 

   public int getSum()  return 1+1;  

public class SimpleClass  
   // properties/getters 

   @JsonIgnore
   public int getSum()  return 1+1;  

【讨论】:

以上是关于Jackson 可以自动将任何构造函数参数视为 JsonProperty 吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥标准不将模板构造函数视为复制构造函数?

Jackson MismatchedInputException(没有从字符串值反序列化的字符串参数构造函数/工厂方法)

构造和析构!

为啥SqlParameter名称/值构造函数将0视为null?

使用 Jackson 从 XML 到 POJO 的反序列化问题:没有从字符串值反序列化的字符串参数构造函数/工厂方法

com.fasterxml.jackson.databind.JsonMappingException 没有从字符串值('1')反序列化的字符串参数构造函数/工厂方法