问题描述:
在Spring框架中,自定义配置了 FastJsonHttpMessageConverter ,覆盖掉 MappingJackson2HttpMessageConverter,导致返回时 序列化出现问题。
预期:
{
"access_token": "f7d77b3f-61f1-4c1e-975e-c6b3bb5f244d",
"token_type": "bearer",
"refresh_token": "35cca126-928a-4429-8bd7-86afb0250559",
"expires_in": 3599,
"scope": "mgtapi_admininfo"
}
实际返回结果:
{
"additionalInformation": {},
"expiration": "2019-03-06 15:49:06",
"expired": false,
"expiresIn": 2141,
"refreshToken": {
"expiration": "2019-03-06 16:49:06",
"value": "35cca126-928a-4429-8bd7-86afb0250559"
},
"scope": [
"mgtapi_admininfo"
],
"tokenType": "bearer",
"value": "f7d77b3f-61f1-4c1e-975e-c6b3bb5f244d"
}
问题定位:
因为在WebMvcConfigurer中自定义配置了消息处理,覆盖了默认的消息处理器
public class BaseWebMvcConfig implements WebMvcConfigurer {
@Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
SerializeConfig config = new SerializeConfig();
config.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
fastJsonConfig.setSerializeConfig(config);
fastConverter.setFastJsonConfig(fastJsonConfig);
return fastConverter;
}
@Override
public void configureMessageConverters(List> converters) {
converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
converters.add(fastJsonHttpMessageConverter());
}
}
读过源码后发现 configureMessageConverters 配置,如果有配置,就会使用用户配置的两种消息处理器,如果没有配置,则会默认添加8个消息处理器。
WebMvcConfigurationSupport.java
protected final List> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
addDefaultHttpMessageConverters(this.messageConverters);
}
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
然而OauthAccessToken 中注解以及内置实现的序列化只支持四种。OAuth2AccessTokenJackson2Serializer 和 OAuth2AccessTokenJackson2Deserializer
@org.codehaus.jackson.map.annotate.JsonSerialize(using = OAuth2AccessTokenJackson1Serializer.class) @org.codehaus.jackson.map.annotate.JsonDeserialize(using = OAuth2AccessTokenJackson1Deserializer.class) @com.fasterxml.jackson.databind.annotation.JsonSerialize(using = OAuth2AccessTokenJackson2Serializer.class) @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = OAuth2AccessTokenJackson2Deserializer.class) public interface OAuth2AccessToken {
问题定位后,就可以着手解决了。方案有很多,我想到了两种。
第一种:
重新一个fastjson的序列化过滤器,针对某一个类做特殊处理。
参考资料:https://github.com/alibaba/fastjson/issues/1640
第二种:
自定义一个消息转换器,并让MappingJackson 消息转换器来处理Oauth2AccessToken的类返回信息。
@Override
public void extendMessageConverters(List> converters) {
Oauth2HttpMessageConverter oauth2HttpMessageConverter = new Oauth2HttpMessageConverter();
converters.add(0, oauth2HttpMessageConverter);
}
Oauth2HttpMessageConverter 类
public class Oauth2HttpMessageConverter extends AbstractHttpMessageConverter {
private final MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
public Oauth2HttpMessageConverter() {
super(MediaType.APPLICATION_JSON_UTF8);
}
@Override
protected boolean supports(Class clazz) {
return clazz.equals(DefaultOAuth2AccessToken.class);
}
@Override
protected DefaultOAuth2AccessToken readInternal(Class clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
throw new UnsupportedOperationException(
"This converter is only used for converting DefaultOAuth2AccessToken to json.");
}
@Override
protected void writeInternal(DefaultOAuth2AccessToken accessToken, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
mappingJackson2HttpMessageConverter.write(accessToken, MediaType.APPLICATION_JSON_UTF8, outputMessage);
}
}
这样的话,Oauth的消息返回时,会被正确处理,就能得到自己想要的结果了。