当前位置: 首页 > 知识库问答 >
问题:

是否可以为不同的数据类型在类级别配置Jackson自定义反序列化器?

西门京
2023-03-14

我需要对一个长而复杂的json进行反序列化,为此我编写了一组java类来映射数据,并且我必须为许多不同类型的字段(包括String、Boolean、BigDecimal等)编写自定义反序列化器。

我知道我可以用相应的自定义反序列化器注释java类中的所有字段(如下所示),但是我需要注释所有类中的几乎所有字段。

@JsonDeserialize(using = CustomBooleanJsonDeserializer.class)
private boolean active;
@Bean
public Module customDeserializersModule() {
    SimpleModule module = new SimpleModule();
    module.addDeserializer(Boolean.class, new CustomBooleanJsonDeserializer());
    // add other custom deserializers 
    return module;
}
@RequestMapping(method = RequestMethod.POST, value = "/data")
public ResponseEntity<ServerInfo> register(@RequestBody DataMapper data) {
   // DataMapper is the target POJO class of the json's deserialization
}
@JsonDeserialize(using = CustomStringJsonDeserializer.class, forType = String.class)
@JsonDeserialize(using = CustomBooleanJsonDeserializer.class, forType = Boolean.class)
@JsonDeserialize(using = CustomBigDecimalJsonDeserializer.class, forType = BigDecimal.class)
public class DataMapper implements Serializable {
    // obviously, @JsonDeserialize doesn't have a forType method
}

或者可以通过某种方式为DataMapper类实现自定义反序列化,该类定义如何根据每个字段的数据类型反序列化每个字段(而不必注释每个字段):

@JsonDeserialize(using = DataMapperJsonDeserializer.class)
public class DataMapper implements Serializable {
    // How can I implement the DataMapperJsonDeserializer with these 
    // characteristics? I know about the ContextualDeserializer interface, 
    // but I don't know how to use it without annotating each field.
}

或者某种将模块的效果限制在一个包或一组类上的方法:

module.restrictedTo(/*some package or set of classes*/);
// com.fasterxml.jackson.databind.Module doesn't have a restrictedTo method

共有1个答案

强保臣
2023-03-14

您可以尝试将SimpleModuleContextualDeserializer接口一起使用。第一个可用于包装默认反序列化程序,第二个可用于检查类型配置-检查注释。

让我们从注释开始:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ForceCustomDeserializer {
}

我假设您只有一个特定类型的自定义实现,但如果不是,请扩展上面的注释并提供一些额外的信息,以便使用正确的反序列化程序。例如,下面我们可以看到两个自定义反序列化程序,它们额外记录一些信息并运行默认的反序列化。使用基本反序列化程序是因为如果您有一些额外的配置,我们不会松动它。

class CustomBoolDeserializer extends StdScalarDeserializer<Boolean> implements ContextualDeserializer {

    private NumberDeserializers.BooleanDeserializer base;

    public CustomBoolDeserializer(NumberDeserializers.BooleanDeserializer base) {
        super(Boolean.class);
        this.base = base;
    }

    @Override
    public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        System.out.println("Custom BooleanDeserializer ....");

        return base.deserialize(p, ctxt);
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        Class<?> parent = property.getMember().getDeclaringClass();
        ForceCustomDeserializer annotation = parent.getAnnotation(ForceCustomDeserializer.class);

        return annotation == null ? base : this;
    }
}

class CustomStringDeserializer extends StringDeserializer implements ContextualDeserializer {

    private final StringDeserializer base;

    public CustomStringDeserializer(StringDeserializer base) {
        this.base = base;
    }

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        System.out.println("Custom StringDeserializer ....");

        return base.deserialize(p, ctxt);
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        Class<?> parent = property.getMember().getDeclaringClass();
        ForceCustomDeserializer annotation = parent.getAnnotation(ForceCustomDeserializer.class);

        return annotation == null ? base : this;
    }
}
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        SimpleModule forcedCustomModule = new SimpleModule();
        forcedCustomModule.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
                if (deserializer instanceof StringDeserializer) {
                    // wrap with yours or return new deserializer
                    return new CustomStringDeserializer((StringDeserializer) deserializer);
                }
                if (deserializer instanceof NumberDeserializers.BooleanDeserializer) {
                    // wrap with yours or return new deserializer
                    return new CustomBoolDeserializer((NumberDeserializers.BooleanDeserializer) deserializer);
                }
                // override for other types

                return deserializer;
            }
        });

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(forcedCustomModule);

        System.out.println(mapper.readValue(jsonFile, Pojo.class));
    }
}

@ForceCustomDeserializer
class Pojo {

    private String name;
    private boolean bool;

    // getters, setters, toString
}
{
  "name": "Jackson",
  "bool": true
}
Custom StringDeserializer ....
Custom BooleanDeserializer ....
Pojo{name='Jackson', bool=true}
  • 使用Jackson反序列化到字符串或对象
  • @在没有控制器的情况下使用jackson创建对象时有效
  • Jackson自定义序列化和反序列化
 类似资料:
  • 我遇到了一个非常有趣的问题,试图让Jackson在自定义序列化程序类创建的JSON中正确删除空字段。我已经非常彻底地搜索了有关序列化程序和SerializationInclusion配置的信息,但我没有找到任何可以解释我所看到的内容的东西。 我配置了一个Jackson对象映射器,并通过Spring自动连接。对象映射器配置和POJO(为简洁起见进行了编辑)看起来或多或少像下面的代码。 出于某种原因,

  • 假设我有以下格式的JSON: 我试图避免自定义反序列化程序,并试图将上述JSON(称为Wrapper.java)反序列化为JavaPOJO。“type”字段指示“object”反序列化,即type=foo表示使用foo.java反序列化“object”字段。(如果type=Bar,则使用Bar.java反序列化对象字段)。Metadata/owner将始终以相同的方式对每个元数据使用简单的带Jac

  • 想象一下以下场景: 我想为Foo编写一个自定义的Jackson反序列化程序。为了做到这一点(例如,为了反序列化具有Foo的类 如何编写这样的反序列化程序?这应该是可能的,因为Jackson是通过键入集合和地图来实现的。 澄清: 似乎有两个部分可以解决这个问题: 1)获取内声明的属性类型并使用它来反序列化

  • 序列化和反序列化的方式不同于 我已经创建了两个序列化程序 和 我用Jackson查看了序列化/反序列化映射 ,但找不到解决方案。

  • 问题内容: 我有一些类型需要使用它们自己的特殊反序列化器和序列化器来处理,但是当类型嵌套在Optional中时,如何指示Jackson使用它们呢? 我正在使用JDK8Module,它适用于不需要任何特殊处理的任何类型。当将@JsonDeserialize和@JsonSerialize批注用于Optional字段时,似乎没有任何方法可应用于Optional内的值: 问题答案: 实现此目的的正确方法是

  • 我想实现一个功能,其中请求映射到正确的对象。是否有一种方法(除了自定义反序列化器)可以将请求按类型/基数映射到适当的对象?任何见解都将不胜感激!