You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 13:35:28