今天在启动spring boot项目,突然出现如下问题:
SLF4J: Failed toString() invocation on an object of type [com.superjson.superjsonmanager.config.jwt.JwtProperties$$EnhancerBySpringCGLIB$$3c58badf]
Reported exception:
com.alibaba.fastjson.JSONException: write javaBean error, fastjson version 1.2.70, class org.springframework.beans.factory.support.DefaultListableBeanFactory, fieldName : $$beanFactory, write javaBean error, fastjson version 1.2.70, class com.baomidou.mybatisplus.MybatisConfiguration, fieldName : configuration, write javaBean error, fastjson version 1.2.70, class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper, fieldName : dataSource, write javaBean error, fastjson version 1.2.70, class com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl, fieldName : connection, write javaBean error, fastjson version 1.2.70, class com.mysql.cj.jdbc.ConnectionImpl, fieldName : connectionRaw, write javaBean error, fastjson version 1.2.70, class com.mysql.cj.jdbc.DatabaseMetaData, fieldName : metaData, write javaBean error, fastjson version 1.2.70, class com.mysql.cj.jdbc.result.ResultSetImpl, fieldName : catalogs
at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:539)
at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:149)
at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:333)
at com.alibaba.fastjson.serializer.ASMSerializer_1_JwtProperties$$EnhancerBySpringCGLIB$$3c58badf.write(Unknown Source)
at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:285)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:758)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:696)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:661)
at com.superjson.superjsonmanager.config.jwt.JwtProperties.toString(JwtProperties.java:73)
at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:277)
at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:249)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:211)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:161)
at ch.qos.logback.classic.spi.LoggingEvent.getFormattedMessage(LoggingEvent.java:293)
at ch.qos.logback.classic.spi.LoggingEvent.prepareForDeferredProcessing(LoggingEvent.java:206)
at ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:223)
at ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:102)
at ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:84)
at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:51)
at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:270)
at ch.qos.logback.classic.Logger.callAppenders(Logger.java:257)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:421)
at ch.qos.logback.classic.Logger.filterAndLog_1(Logger.java:398)
at ch.qos.logback.classic.Logger.info(Logger.java:583)
at com.superjson.superjsonmanager.SuperJsonManagerApplication.main(SuperJsonManagerApplication.java:51)
Caused by: com.alibaba.fastjson.JSONException: write javaBean error, fastjson version 1.2.70, class com.baomidou.mybatisplus.MybatisConfiguration, fieldName : configuration, write javaBean error, fastjson version 1.2.70, class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper, fieldName : dataSource, write javaBean error, fastjson version 1.2.70, class com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl, fieldName : connection, write javaBean error, fastjson version 1.2.70, class com.mysql.cj.jdbc.ConnectionImpl, fieldName : connectionRaw, write javaBean error, fastjson version 1.2.70, class com.mysql.cj.jdbc.DatabaseMetaData, fieldName : metaData, write javaBean error, fastjson version 1.2.70, class com.mysql.cj.jdbc.result.ResultSetImpl, fieldName : catalogs
at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:539)
at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:149)
at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:333)
at com.alibaba.fastjson.serializer.ASMSerializer_105_DefaultSqlSessionFactory.write(Unknown Source)
at com.alibaba.fastjson.serializer.MapSerializer.write(MapSerializer.java:271)
at com.alibaba.fastjson.serializer.MapSerializer.write(MapSerializer.java:44)
at com.alibaba.fastjson.serializer.FieldSerializer.writeValue(FieldSerializer.java:320)
at com.alibaba.fastjson.serializer.JavaBeanSerializer.write(JavaBeanSerializer.java:470)
... 24 more
上述问题总结一句话是,使用alibaba.fastjson
解析Javabean
对象时,出现了错误,但为什么会出现这个问题呢?
我使用alibaba.fastjson
解析JwtProperties
对象报出上述错误的,该对象是用来存储jwt
的参数,如下代码所示:
/**
* @author zby
* @datetime 2022/8/19 12:05
* @desc jwt实体类,从yml配置文件中获取配置的属性
*/
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "jwt")
public class JwtProperties {
@Value("${jwt.secret}")
private String appSecret;
@Value("${jwt.expiration}")
private long expiration;
@Value("${jwt.typ}")
private String typ;
@Value("${jwt.alg}")
private String alg;
@Value("${jwt.subject}")
private String subject;
@Value("${jwt.tokenStartWith}")
private String tokenStartWith;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
public String getTokenStartWith() {
return tokenStartWith + " ";
}
@Override
@JSONField(serialize = false)
public String toString() {
return JSONObject.toJSONString(this);
}
}
即重写toString()
方法内部语句JSONObject.toJSONString(this);
时出现了问题,于是断点看为何会出现这种问题,如下截图所示:
你会发现动态生成的JwtProperties的this对象
并不是只有其属性值,而是还多了很多我并没有定义的属性值,为什么会出现这种情况呢?
应为spring boot
采用动态代理的模式去实例化对象的,而这额外的属性值便是动态代理对象的属性值,因而,fastjson
无法解析动态代理的属性值,故而报错。
既然知道错误的原因是spring boot
动态代理造成的,我们便不把对象交给spring boot
动态代理,可以进行如下修改toString()
方法:
@Override
@JSONField(serialize = false)
public String toString() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("appSecret", this.appSecret);
jsonObject.put("expiration", this.expiration);
jsonObject.put("typ", this.typ);
jsonObject.put("alg", this.alg);
jsonObject.put("subject", this.subject);
jsonObject.put("tokenStartWith", this.tokenStartWith);
jsonObject.put("tokenHeader", this.tokenHeader);
return JSONObject.toJSONString(jsonObject);
}
如此启动spring boot
即可,如下图所示: