乐趣区

关于java:给ShardingSphere提了个PR不知道是不是嫌弃我

说来惭愧,干了 10 来年程序员,还没有给开源做过任何奉献,以前只晓得嘎嘎写,出了问题嘎嘎改,素来没想过提个 PR 去修复他,最近碰到个问题,发现挺简略的,就顺手提了个 PR 过来。

问题

问题挺简略的,就是在应用 mybatis 和 ShardingSphere 的时候,有人在 model 类应用了 OffsetDateTime 这个工夫类型,发现会报错。

Caused by: java.lang.ClassCastException: class java.sql.Timestamp cannot be cast to class java.time.OffsetDateTime (java.sql.Timestamp is in module java.sql of loader 'platform'; java.time.OffsetDateTime is in module java.base of loader 'bootstrap')
    at org.apache.ibatis.type.OffsetDateTimeTypeHandler.getNullableResult(OffsetDateTimeTypeHandler.java:38)
    at org.apache.ibatis.type.OffsetDateTimeTypeHandler.getNullableResult(OffsetDateTimeTypeHandler.java:28)
    at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85)
    ... 99 more

这就是一个简略的类型转换的异样,于是跟着源码看了下,先看到 BaseTypeHandler#getResult 这个办法,实际上就是依据列名返回查问后果。

依据调用关系,找到了 OffsetDateTimeTypeHandler 实现类。

发现最终会调用 rs.getObject() 这个办法,那么其实这个办法会最终走到由 ShardingSphere 实现的 getObject办法中。

看到这里的时候其实曾经明确了为啥会报错了,Shardingsphere 只判断了几个 LocalDateTime 等类型,对于这个比拟非凡的工夫类型没有解决,最终会转换成 Timestamp,而后强转就报错了。

最初调用到 ResultSetUtil#convertTimestampValue 办法,能够看到的确是这样哈。

那如果批改源码的话其实很简略了,getObject判断多加一个,convertTimestampValue再加一个,就这样很简略啊。

@Override
    public <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException {if (BigInteger.class.equals(type)) {return (T) BigInteger.valueOf(getLong(columnIndex));
        } else if (Blob.class.equals(type)) {return (T) getBlob(columnIndex);
        } else if (Clob.class.equals(type)) {return (T) getClob(columnIndex);
        } else if (LocalDateTime.class.equals(type) || LocalDate.class.equals(type) || LocalTime.class.equals(type) || OffsetDateTime.class.equals(type)) {return (T) ResultSetUtil.convertValue(mergeResultSet.getValue(columnIndex, Timestamp.class), type);
        } else {return (T) ResultSetUtil.convertValue(mergeResultSet.getValue(columnIndex, type), type);
        }
    }
    
private static Object convertTimestampValue(final Object value, final Class<?> convertType) {Timestamp timestamp = (Timestamp) value;
        if (LocalDateTime.class.equals(convertType)) {return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();}
        if (LocalDate.class.equals(convertType)) {return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();}
        if (LocalTime.class.equals(convertType)) {return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();}
        if (OffsetDateTime.class.equals(convertType)) {return timestamp.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();}
        return value;
}

修复

最开始我其实并不想改源码,我在想其余的实现计划,搜寻后发现引入一个包就能够解决,也就是 mybatis 的 JSR310 标准。

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-typehandlers-jsr310</artifactId>
  <version>1.0.1</version>
</dependency>

他为什么能解决这个问题?我看了下他的包外面的代码,这不就是加了个 TypeHandler 本人解决了嘛。

再去看了下 OffsetDateTimeTypeHandler的实现,其实就是本人就解决了,间接给返回OffsetDateTime,基本不会走到 ShardingSphere 的逻辑外面去,这也就是他能解决这个问题的起因了。

当然,如果不想那么麻烦引入一个包,也能够独自把他拎进去本人去指定一下,这个很简略,就不多说了。

提 PR

于是我想,这事件这么简略,我不如提个 PR 给官网吧,这里教下大家怎么提 PR。

因为不是咱们的我的项目,是没法 push 代码的,所以进入到我的项目,而后fork,fork 好了当前,间接把我的项目 clone 下来,而后执行命令。

git remote add upstream https://github.com/apache/shardingsphere.git

通过命令咱们能够看到胜利了,这样就 OK 了,而后失常拉分支写代码吧。

写完之后,失常去咱们的我的项目界面提交 PR,而后就能够了。

麻烦

当然,过程并没有这么顺利,尽管说只是很简略的批改。

首先,这个校验就给我提醒谬误了,第一点叫我不要用 *号去援用。

这个其实是 IDEA的锅,如果援用同一个包下类过多的话,会主动帮咱们转成星号,这个咱们能够在Editor-Code Style-Java,而后找到 Imports 下的这两个选项,把他们都改成 99 就能够了,避免他主动给咱们改成星号。

还有一些其余的比方 if 前面没跟空格之类的,这是我遗记格式化了!

而后大佬回复感觉看不下去,这代码太恶心了,说咱们是不是能够用 java.time.temporal.TemporalAccessor 来判断,不然这么多工夫类型,搞个毛线呢。

而后我就翻译了一段英文,我也不晓得大佬看没看懂,我通知他,这个不好整啊,你看这个接口啊,很多乌七八糟的类实现了他,实际上我感觉咱们笼罩罕用的一些就行了,其余的非凡工夫类型让他们本人用 TypeHandler 解决吧。

大佬说,嗯当然,没方法判断这个接口那咱们也没辙了,我说那不可就是嘛。

其实,还有很多工夫类型他都会报错的,最好的方法这个都形象进去和 Mybatis 独自用实现类,不过那样的话就得大工作了,我太懒了,就这样。

。。。

工夫过来了几天,看了下他还没合我代码,是不是厌弃我?

退出移动版