Hibernate Spatial 6迁移PostGIS函数遇两类问题求助
Hibernate Spatial 6.1.7.Final 迁移问题解决方案
问题1:调用PostGIS geography 函数抛出 IllegalArgumentException
错误信息
java.lang.IllegalArgumentException: Passed `invariantType` for function return cannot be null at org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.invariant(StandardFunctionReturnTypeResolvers.java:45) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final] at org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder.function(SqmCriteriaNodeBuilder.java:1495) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final] at org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder.function(SqmCriteriaNodeBuilder.java:153) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final] at com.adani.amm.specification.AssetLocationSpecification.toPredicate(AssetLocationSpecification.java:35) ~[classes/:na]
原因
Hibernate Spatial 6 对空间函数的注册和类型解析逻辑做了严格调整,不再支持直接通过criteriaBuilder.function调用未注册的geography函数,原代码中手动指定返回类型的方式也不再适配新的类型系统。
解决方案
放弃手动调用geography函数,改用Hibernate Spatial 6 提供的SpatialCriteriaBuilder构建类型安全的空间查询,同时利用PostGIS的ST_DWithin自动处理地理坐标的球面距离计算。重构后的代码如下:
import org.hibernate.spatial.criteria.SpatialCriteriaBuilder; import org.hibernate.spatial.criteria.SpatialPredicates; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.PrecisionModel; import org.springframework.data.jpa.domain.Specification; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; public class AssetLocationSpecification implements Specification<Location> { private static final long serialVersionUID = 1L; private final Double radius; private final Double latitude; private final Double longitude; // 预定义WGS84坐标系的Geometry工厂 private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(new PrecisionModel(), 4326); public AssetLocationSpecification(Double radius, Double latitude, Double longitude) { this.radius = radius; this.latitude = latitude; this.longitude = longitude; } @Override public Predicate toPredicate(Root<Location> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { // 转为SpatialCriteriaBuilder以使用空间查询API SpatialCriteriaBuilder spatialBuilder = criteriaBuilder.unwrap(SpatialCriteriaBuilder.class); // 创建WGS84坐标系的中心点 Point centerPoint = GEOMETRY_FACTORY.createPoint(new org.locationtech.jts.geom.Coordinate(longitude, latitude)); // 直接调用dwithin方法,自动适配PostGIS的ST_DWithin函数 return SpatialPredicates.dwithin(spatialBuilder, root.get("geometry"), centerPoint, radius); } }
同时确保实体类中geometry字段的注解明确指定地理类型:
import jakarta.persistence.Column; import jakarta.persistence.Entity; import org.locationtech.jts.geom.Geometry; @Entity public class Location { // 其他字段... @Column(columnDefinition = "geography(Point, 4326)") private Geometry geometry; // getter/setter... }
问题2:SpatialFunction.dwithin 废弃但CommonSpatialFunction无对应枚举
原因
Hibernate Spatial 6 重构了空间查询API,废弃了原有的SpatialFunction枚举,转而通过SpatialCriteriaBuilder和SpatialPredicates提供类型安全的静态方法,不再需要手动指定函数名枚举。
解决方案
直接使用SpatialPredicates中的静态方法构建空间查询,比如SpatialPredicates.dwithin,这些方法已经封装了对应的PostGIS函数调用,无需手动处理函数名。如果需要调用其他空间函数,可通过SpatialCriteriaBuilder.function方法,它会自动处理函数注册和类型解析,避免出现类型为空的错误。
内容的提问来源于stack exchange,提问作者Urman Ratneshwar
相关产品推荐
相关产品推荐

