我需要反序列化一个冗长而复杂的json,为此我编写了一组Java类来映射数据,并且我不得不为许多不同类型(包括String,Boolean,BigDecimal,等)。
我知道我可以使用相应的自定义反序列化器(如下所示)来注释java类中的所有字段,但是然后我将需要注释所有类中的几乎所有字段。
@JsonDeserialize(using = CustomBooleanJsonDeserializer.class)
private boolean active;
我也知道我可以在Spring默认的ObjectMapper
中注册一个模块(例如here),但是我只想对这些特定的类使用这些自定义反序列化器。
@Bean
public Module customDeserializersModule() {
SimpleModule module = new SimpleModule();
module.addDeserializer(Boolean.class, new CustomBooleanJsonDeserializer());
// add other custom deserializers
return module;
}
我什至知道我可以在ObjectMapper
中使用自定义RestController
,但是我不想放弃通过@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
类实现自定义反序列化器的某种方式,该类定义了如何根据其数据类型对每个字段进行反序列化(而不必注释每个字段):< / p>
@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
答案 0 :(得分:2)
您可以尝试将SimpleModule
与ContextualDeserializer
界面一起使用。第一个可用于包装默认的反序列化器,第二个可用于检查类型配置-检查注释。
让我们从注释开始:
@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}
另请参阅:
答案 1 :(得分:0)
您可以为该类定义一个自定义反序列化器(作为问题中的第二个想法 ),并在其中使用您自己的自定义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 Mix-in Annotations( the DefaultJsonDeserializer
接口)从POJO
类中动态删除自定义解串器,避免否则会由于objectMapper.readValue(jsonParser, DataMapper.class)
而引发的StackOverflowError
。
然后,仅用于注释POJO
类:
@JsonDeserialize(using = DataMapperJsonDeserializer.class)
public class DataMapper implements Serializable {
// It is not necessary to annotate each field with custom deserializers.
}
您甚至可以将其他POJO
类添加为DataMapper
的字段,每种类型的自定义反序列化器将自动应用于其字段,而无需注释。