解决oracle.sql.TIMESTAMP序列化转换失败问题 及 J2EE13Compliant原理

报错现象

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,可能会导致序列化时类型转换失败等问题

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值