我正在开发一个 Spring MVC 项目,我需要全局覆盖 Jackson 提供的默认
StringDeserializer
来清理传入的 JSON 字符串。我的目标是将这种清理应用于 DTO 中的所有 String
字段,而无需单独注释每个字段(要覆盖超过 200 个 DTO)。
我创建了一个自定义 StringDeserializer 并将其添加到 Spring 配置中,但从未被调用。
自定义解串器:
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
public class SanitizeDeserializer extends StringDeserializer {
@Override
public String deserialize(
final JsonParser aParser,
final DeserializationContext aContext) throws IOException {
// this code is never executed
return Jsoup.clean(super.deserialize(aParser, aContext), Safelist.none());
}
}
注册反序列化器的 Spring 配置:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
@Configuration
public class SanitizeConfiguration {
@Bean
public Module addSanitizeStringDeserializer() {
// this code is well executed when running the app
final SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, new SanitizeDeserializer());
return module;
}
}
REST 控制器示例:
@PutMapping("/document/{id}")
public ResponseEntity<String> save(@RequestBody DocumentDTO document) {
return ResponseEntity.ok(document.getId());
}
@Getters
@Setters
public class DocumentDTO {
// I want these String fields to be sanitize before the setter is called when deserializing the JSON
private String id;
private String title;
private String content;
}
我在 deserialize 方法中放置了一个断点,但它从未被调用,它在 Jackson StringDeserializer 方法中中断。
我做错了什么,还是我缺少配置?
或者在已经定义的类型上自定义序列化器可能不可行?
编辑1:
我尝试配置
MessageConverters
,但它覆盖了默认配置 (WebMvcConfigurationSupport.addDefaultHttpMessageConverters
),虽然所有字符串字段都由自定义反序列化器很好地反序列化,但 XML 内容转换无法像以前一样工作。
@Override
public void configureMessageConverters(
final List<HttpMessageConverter<?>> aConverters) {
final Jackson2ObjectMapperBuilder iBuilder = new Jackson2ObjectMapperBuilder().deserializerByType(String.class,
new SanitizeDeserializer());
aConverters.add(new MappingJackson2HttpMessageConverter(iBuilder.build()));
// if i remove the following line, the XML response are not handle (500 error)
// but with this line, XML reponse are XML escaped and become invalid
aConverters.add(new MappingJackson2XmlHttpMessageConverter(new Jackson2ObjectMapperBuilder().xml().build()));
}
然后我尝试了评论中的建议,添加一个
Jackson2ObjectMapperBuilder
Bean,但仍然没有使用:
@Bean
public Jackson2ObjectMapperBuilder configureJackson2ObjectMapperBuilder() {
final Jackson2ObjectMapperBuilder iBuilder = new Jackson2ObjectMapperBuilder();
final SimpleModule iSanitizeModule = new SimpleModule("sanitize-module");
iSanitizeModule.addDeserializer(String.class, new SanitizeDeserializer());
iBuilder.modules(iSanitizeModule);
return iBuilder;
}
@Bean
public MappingJackson2HttpMessageConverter configureMappingJackson2HttpMessageConverter() {
final MappingJackson2HttpMessageConverter iConverter = new MappingJackson2HttpMessageConverter();
iConverter.setObjectMapper(configureJackson2ObjectMapperBuilder().build());
return iConverter;
}
这是可行的解决方案,保留默认的 Spring
MessageConverters
,并在 Jackson JSON 转换器中添加自定义的反序列化器。
自定义代码
Deserializer
public class SanitizeDeserializer extends StringDeserializer {
@Override
public String deserialize(
final JsonParser aParser,
final DeserializationContext aContext) throws IOException {
return Jsoup.clean(super.deserialize(aParser, aContext), Safelist.none());
}
}
然后,在扩展
@EnableWebMvc
的 WebMvcConfigurer
类中,重写 extendMessageConverters
以将默认的 Jackson JSON MessageConverter 替换为您的自定义消息转换器:
@Override
public void extendMessageConverters(
final List<HttpMessageConverter<?>> aConverters) {
aConverters.removeIf(MappingJackson2HttpMessageConverter.class::isInstance);
final Jackson2ObjectMapperBuilder iBuilder = new Jackson2ObjectMapperBuilder().deserializerByType(String.class,
new SanitizeDeserializer());
aConverters.add(new MappingJackson2HttpMessageConverter(iBuilder.build()));
}