今天运行一个工程时候发现突然发现以前写的Jackson配置全局过滤值为null的字段的类失效了。这个配置类代码如下:
@Configuration
public class JacksonConfig {
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化,就是为null的字段不参加序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 字段保留,将null值转为""
// objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
// @Override
// public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
// jsonGenerator.writeString("");
// }
// });
return objectMapper;
}
}
排查了半天发现是因为之前将spring boot工程由1.5.10.RELEASE升级到了2.0.1RELEASE,然后IDEA提示拦截器继承的WebMvcConfigurerAdapter类是过时的,就换成了WebMvcConfigurationSupport。改回WebMvcConfigurerAdapter就有效了。非常纳闷于是去网上查了查,大部分都是这样的说明,详见[https://blog.csdn.net/lqadam/article/details/80637335 ]
1.@EnableWebMvc=WebMvcConfigurationSupport,使用了@EnableWebMvc注解等于扩展了WebMvcConfigurationSupport但是没有重写任何方法
2.@EnableWebMvc+extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
3.extends WebMvcConfigurationSupport,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
4.extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式依旧使用springboot的@EnableAutoConfiguration中的设置
很是不解既然默认配置不是spring boot的一大特色吗,那为什么还有WebMvcConfigurationSupport这种东西。
可能是了解的太少吧,留着这个疑惑慢慢思考,先解决当前的问题。过时的WebMvcConfigurerAdapter带着刺眼的横线,这无疑会污染我的代码,影响编码心情。
查看WebMvcConfigurationAdapter源码,Doc规范告诉我们过时类都会在源码注释中给出推荐使用的替代类。果然发现以下说明:
/**
* An implementation of {@link WebMvcConfigurer} with empty methods allowing
* subclasses to override only the methods they're interested in.
*
* @author Rossen Stoyanchev
* @since 3.1
* @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
* possible by a Java 8 baseline) and can be implemented directly without the
* need for this adapter
*/
@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
...
}
意思就是Java8给出了新的特性,使得接口方法可以拥有默认实现。所以你现在可以直接实现WebMvcConfigurer而不用像以前那样通过继承它的实现类来达到目的。
OK,文档说的很明白了,换成实现WebMvcConfigurer方式确实解决了问题。
不过新的疑问又出来了,为什么Java8要弄个接口默认方法呢,这有什么特别的地方吗?这个倒是很容易想明白。进入WebMvcConfigurer类查看源码,可以发现其中定义了大量的方法。与WebMvcConfigurerAdapter进行对比可以发现,虽然WebMvcConfigurerAdapter实现了WebMvcConfigurer接口,但是大量的实现都是空实现啊。。。
...
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
}
...
做成这样是因为Java的单继承多实现规则,一个类可能同时需要WebMvcConfigurer和其他类中的方法,用继承的方式限制了这一点。而WebMvcConfigurer中的方法也不是在每个地方都会用到,所以写了一些特定场合的适配,这样就可以按需继承对应的适配器,而自己的定制实现通过多态性对外展示为WebMvcConfigurer,使框架能够降低耦合度。
但对于追求完美的编程人员,这显然无法令人满意。于是出现了带有默认实现的接口,这样在使用的时候只需要实现自己想要的方法就行了,不用再去手动空实现或编写适配器。果然懒是第一创造力。