报错现象
oracle表中存在TIMESTAMP类型的列时,jdbc查出来做序列化时报错
报错内容
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class java.io.ByteArrayInputStream]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.oxye.ResMsg["data"]->com.oxye.base.dto.BaseResponse["columns"]->java.util.ArrayList[0]->java.util.ArrayList[10]->oracle.sql.TIMESTAMP["stream"])
---
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class java.io.ByteArrayInputStream]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.oxye.ResMsg["data"]->com.oxye.base.dto.BaseResponse["columns"]->java.util.ArrayList[0]->java.util.ArrayList[10]->oracle.sql.TIMESTAMP["stream"])
---
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.oxye.ResMsg["data"]->com.oxye.base.dto.BaseResponse["columns"]->java.util.ArrayList[0]->java.util.ArrayList[10]->oracle.sql.TIMESTAMP["stream"])
处理方法
任选其一,目的就是设置一个变量:
1.项目启动时设置一行代码 System.setProperty(“oracle.jdbc.J2EE13Compliant”, “true”);
2.jar启动命令增加 -Doracle.jdbc.J2EE13Compliant=true
3.oracle连接串中增加属性oracle.jdbc.J2EE13Compliant=true
Oracle驱动源码
版本
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.9.0.0</version>
</dependency>
oracle.jdbc.driver.GeneratedPhysicalConnection类有属性j2ee13Compliant,可以看到
readConnectionProperties中会从多处寻找属性oracle.jdbc.J2EE13Compliant,找不到默认是false
/***/
abstract class GeneratedPhysicalConnection extends OracleConnection {
boolean j2ee13Compliant;
/***/
protected void readConnectionProperties(String var1, @Blind(PropertiesBlinder.class) Properties var2, @Blind(PropertiesBlinder.class) Properties var3) throws SQLException {
/***/
var4 = null;
if (var2 != null) {
var4 = var2.getProperty("oracle.jdbc.J2EE13Compliant");
}
if (var4 == null) {
var4 = getSystemProperty("oracle.jdbc.J2EE13Compliant", (String)null);
}
if (var4 == null && var3 != null) {
var4 = var3.getProperty("oracle.jdbc.J2EE13Compliant");
}
if (var4 == null) {
var4 = "false";
}
this.j2ee13Compliant = var4 != null && var4.equalsIgnoreCase("true");
/***/
oracle.jdbc.driver.TimestampAccessor的getObject方法中,会根据属性j2ee13Compliant选择获取时间的方式
/***/
class TimestampAccessor extends DateTimeCommonAccessor {
/***/
Object getObject(int var1) throws SQLException {
if (!this.isUseLess && !this.isNull(var1)) {
if (this.externalType == 0) {
return this.statement.connection.j2ee13Compliant ? this.getTimestamp(var1) : this.getTIMESTAMP(var1);
} else {
switch (this.externalType) {
case 93:
return this.getTimestamp(var1);
default:
throw (SQLException)((SQLException)DatabaseError.createSqlException(this.getConnectionDuringExceptionHandling(), 4).fillInStackTrace());
}
}
} else {
return null;
}
}
/***/
oracle.jdbc.driver.DateTimeCommonAccessor有两个方法getTimestamp和getTIMESTAMP,j2ee13Compliant为true时用getTimestamp获得java.sql.Timestamp,false获取oracle.sql.TIMESTAMP
/***/
import java.sql.Timestamp;
/***/
import oracle.sql.TIMESTAMP;
/***/
abstract class DateTimeCommonAccessor extends Accessor {
/***/
Timestamp getTimestamp(int var1) throws SQLException {
return this.getTimestamp(var1, (Calendar)null);
}
/***/
TIMESTAMP getTIMESTAMP(int var1) throws SQLException {
return this.isNull(var1) ? null : new TIMESTAMP(this.getBytesInternal(var1));
}
/***/
总结
通过设置属性oracle.jdbc.J2EE13Compliant=true,可以时oracle的timestamp以oracle.sql.TIMESTAMP类型返回,不设置时默认false,返回oracle.sql.TIMESTAMP,可能会导致序列化时类型转换失败等问题