为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

凤凰求蛊 2022-09-14 17:33:30
我需要反序列化一个长而复杂的json,为此我编写了一组java类来映射数据,并且我必须为许多不同类型的字段(包括字符串,布尔,BigDecimal等)编写自定义反序列化器。我知道我可以使用相应的自定义反序列化程序(如下所示)注释java类中的所有字段,但是我需要注释所有类中的几乎所有字段。@JsonDeserialize(using = CustomBooleanJsonDeserializer.class)private boolean active;我也知道我可以在Spring默认值中注册一个模块(就像这里一样),但我只想将这些自定义反序列化程序用于这些特定的类。ObjectMapper@Beanpublic Module customDeserializersModule() {    SimpleModule module = new SimpleModule();    module.addDeserializer(Boolean.class, new CustomBooleanJsonDeserializer());    // add other custom deserializers     return module;}我甚至知道我可以在中使用自定义,但我不想放弃通过 自动数据绑定的便利性,因为我必须防止其他人在没有必要的自定义反序列化程序的情况下使用它。ObjectMapperRestController@RequestBody@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
查看完整描述

2 回答

?
慕运维8079593

TA贡献1876条经验 获得超5个赞

您可以为类定义自定义反序列化程序(作为问题中的第二个想法),并在内部使用自己的自定义:ObjectMapper


public class DataMapperJsonDeserializer extends JsonDeserializer<DataMapper> {


    private static final ObjectMapper objectMapper = new ObjectMapper();

    private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");


    static {

        SimpleModule module = new SimpleModule();

        module.addDeserializer(BigInteger.class, new CustomBigIntegerJsonDeserializer());

        module.addDeserializer(BigDecimal.class, new CustomBigDecimalJsonDeserializer());

        module.addDeserializer(Boolean.class, new CustomBooleanJsonDeserializer());

        module.addDeserializer(String.class, new CustomStringJsonDeserializer());

        objectMapper.registerModule(module);

        objectMapper.addMixIn(DataMapper.class, DefaultJsonDeserializer.class);

        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        objectMapper.setDateFormat(simpleDateFormat);

    }


    @Override

    public DataMapper deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

        return objectMapper.readValue(jsonParser, DataMapper.class);

    }


    @JsonDeserialize

    private interface DefaultJsonDeserializer {

        // Reset default json deserializer

    }


}

请注意使用 Jackson 混合注释(接口)从类中动态删除自定义反序列化程序,从而避免堆栈溢出错误,否则由于 而会引发。DefaultJsonDeserializerPOJOobjectMapper.readValue(jsonParser, DataMapper.class)


然后,只需注释类:POJO


@JsonDeserialize(using = DataMapperJsonDeserializer.class)

public class DataMapper implements Serializable {

    // It is not necessary to annotate each field with custom deserializers.

}

您甚至可以将其他类添加为 的字段,并且每种类型的自定义反序列化程序将自动应用于其字段,而无需注释。POJODataMapper


查看完整回答
反对 回复 2022-09-14
?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

您可以尝试将简单模块上下文序列化程序接口一起使用。第一个可用于包装默认的去细节,第二个用于检查类型配置 - 检查注释。

让我们从注释开始:

@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

}

以上示例为以下有效负载:JSON


{

  "name": "Jackson",

  "bool": true

}

指纹:


Custom StringDeserializer ....

Custom BooleanDeserializer ....

Pojo{name='Jackson', bool=true}


查看完整回答
反对 回复 2022-09-14
  • 2 回答
  • 0 关注
  • 123 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信