Quarkus 3.2.4中Hibernate Reactive Geometry映射遇ClassCastException
Quarkus Hibernate Reactive Panache + MySQL空间类型 ClassCastException 问题分析
这确实是一个兼容性Bug,仅在MySQL + Hibernate Reactive场景下触发,PostgreSQL正常是因为对应的Reactive方言已适配了客户端的空间类型处理逻辑。
问题原因
Hibernate Spatial的MySQL方言在Reactive模式下,仍沿用传统JDBC的处理方式,尝试将数据库返回的空间类型读取为Buffer字节流;但Vertx MySQL客户端会直接把MySQL的POINT类型映射为io.vertx.mysqlclient.data.spatial.Point对象,而非原始WKB字节,这就导致了类型强制转换失败(Point无法转为Buffer)。
解决方案
方案1:升级Quarkus版本
Quarkus 3.3及后续版本已经修复了Hibernate Reactive与MySQL空间类型的适配问题,直接升级到最新稳定版即可解决该错误。
方案2:临时自定义类型适配(无法升级时)
如果暂时无法升级Quarkus,可以自定义一个JdbcType来适配Vertx返回的空间类型,实现io.vertx.mysqlclient.data.spatial.Point到org.locationtech.jts.geom.Point的转换:
- 自定义JdbcType实现类:
import io.vertx.mysqlclient.data.spatial.Point; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.BasicBinder; import org.hibernate.type.descriptor.jdbc.BasicExtractor; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; public class MySQLReactiveGeometryType implements JdbcType { private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(); @Override public int getJdbcTypeCode() { return Types.OTHER; } @Override public <X> ValueBinder<X> getBinder(JavaType<X> javaType) { return new BasicBinder<>(javaType, this) { @Override protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { org.locationtech.jts.geom.Point jtsPoint = javaType.unwrap(value, org.locationtech.jts.geom.Point.class, options); Point vertxPoint = new Point(jtsPoint.getX(), jtsPoint.getY()); st.setObject(index, vertxPoint); } }; } @Override public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) { return new BasicExtractor<>(javaType, this) { @Override protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { Point vertxPoint = rs.getObject(paramIndex, Point.class); org.locationtech.jts.geom.Point jtsPoint = GEOMETRY_FACTORY.createPoint( new Coordinate(vertxPoint.getX(), vertxPoint.getY()) ); return javaType.wrap(jtsPoint, options); } }; } }
- 在实体类的
geom字段上指定该自定义类型:
@Column(columnDefinition = "geometry") @Type(MySQLReactiveGeometryType.class) public Point geom;
注意:确保项目依赖中已包含
io.quarkus:quarkus-hibernate-reactive-spatial依赖。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

