Skip to content

Hibernate spatial with PostGIS failing when running in native #505

@loonis

Description

@loonis

Describe the bug

Hibernate spatial is failing when running in native image.

To Reproduce

Create a spring boot 3.3.1 project using hibernate-spatial

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.1</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<groupId>com.test</groupId>
	<artifactId>test</artifactId>


	<version>0.0.1-SNAPSHOT</version>
	<name>test</name>
	<description>Demo project for Spring Boot</description>


	<properties>
		<java.version>21</java.version>
		<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
		<graphql-java-extended-scalars.version>22.0</graphql-java-extended-scalars.version>
		<hibernate.version>6.5.2.Final</hibernate.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>com.google.cloud</groupId>
				<artifactId>spring-cloud-gcp-dependencies</artifactId>
				<version>5.4.1</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-graphql</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>

		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>com.graphql-java</groupId>
			<artifactId>graphql-java-extended-scalars</artifactId>
			<version>${graphql-java-extended-scalars.version}</version>
		</dependency>

		<dependency>
			<artifactId>mapstruct</artifactId>
			<groupId>org.mapstruct</groupId>
			<version>${org.mapstruct.version}</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate.orm</groupId>
			<artifactId>hibernate-spatial</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<dependency>
			<groupId>com.google.cloud</groupId>
			<artifactId>spring-cloud-gcp-starter-sql-postgresql</artifactId>
		</dependency>


<!--		TESTS-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webflux</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.graphql</groupId>
			<artifactId>spring-graphql-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>${maven-compiler-plugin.version}</version>
				<executions>
					<execution>
						<id>default-compile</id>
						<phase>compile</phase>
						<goals>
							<goal>compile</goal>
						</goals>
					</execution>
					<execution>
						<id>default-testCompile</id>
						<phase>test-compile</phase>
						<goals>
							<goal>testCompile</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<annotationProcessorPaths>
						<path>
							<artifactId>mapstruct-processor</artifactId>
							<groupId>org.mapstruct</groupId>
							<version>${org.mapstruct.version}</version>
						</path>
						<path>
							<artifactId>lombok</artifactId>
							<groupId>org.projectlombok</groupId>
							<version>${lombok.version}</version>
						</path>

						<path>
							<groupId>org.hibernate.orm</groupId>
							<artifactId>hibernate-jpamodelgen</artifactId>
							<version>${hibernate.version}</version>
						</path>


					</annotationProcessorPaths>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>io.github.deweyjose</groupId>
				<artifactId>graphqlcodegen-maven-plugin</artifactId>
				<version>1.61.0</version>
				<executions>
					<execution>
						<id>dgs-codegen</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>generate</goal>
						</goals>
						<configuration>
							<schemaPaths>
								<param>src/main/resources/graphql</param>
							</schemaPaths>
							<packageName>com.kc.dto</packageName>
							<addGeneratedAnnotation>true</addGeneratedAnnotation>
							<generateClientApiV2>false</generateClientApiV2>
							<generateDataTypes>true</generateDataTypes>

							<onlyGenerateChanged>false</onlyGenerateChanged>
							<addGeneratedAnnotation>true</addGeneratedAnnotation>
						</configuration>
					</execution>
				</executions>
			</plugin>

			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>build-helper-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>add-dgs-source</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>${project.build.directory}/generated-sources</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>

			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>build-image</goal>
						</goals>
					</execution>
				</executions>



				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.hibernate.orm.tooling</groupId>
				<artifactId>hibernate-enhance-maven-plugin</artifactId>
				<version>${hibernate.version}</version>
				<executions>
					<execution>
						<configuration>
							<failOnError>true</failOnError>
							<enableLazyInitialization>true</enableLazyInitialization>
						</configuration>
						<goals>
							<goal>enhance</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

			<plugin>
				<groupId>org.graalvm.buildtools</groupId>
				<artifactId>native-maven-plugin</artifactId>
			</plugin>

		</plugins>
	</build>
</project>
spring:
  jpa:
    properties:
      hibernate:
        format_sql=true:
    defer-datasource-initialization: true
    hibernate:
      ddl-auto: none

One of my entity contains a field org.locationtech.jts.geom.Point; which is a PostGIS GEOGRAPHY(POINT, 4326),

I filter my entities based on these gps coordinates

      org.locationtech.jts.geom.GeometryFactory geometryFactory = new GeometryFactory();
      org.locationtech.jts.geom.Point refPoint = geometryFactory.createPoint(new Coordinate(latitude, longitude));
      refPoint.setSRID(4326);

      jakarta.persistence.criteria.Predicate distancePredicate = cb.equal(cb.literal(true), cb.function(
          "ST_DWithin",
          Boolean.class,
          root.get("location"),
          cb.literal(refPoint),
          cb.literal(radiusMeter)
      ));

The native image generation is working, but then running the executable will generate these error log bellow.

Error 1

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.geolatte.geom.crs.CrsRegistry
        at org.geolatte.geom.jts.JTS.determineCrsFromCoordinatesAndSrid(JTS.java:163) ~[na:na]
        at org.geolatte.geom.jts.JTS.from(JTS.java:126) ~[na:na]
        at org.hibernate.spatial.JTSGeometryJavaType.unwrap(JTSGeometryJavaType.java:102) ~[na:na]
        at org.hibernate.spatial.JTSGeometryJavaType.unwrap(JTSGeometryJavaType.java:37) ~[na:na]

Error2

Caused by: java.lang.InstantiationException: org.geolatte.geom.codec.PostgisWkbDecoder
        at [email protected]/java.lang.Class.newInstance(DynamicHub.java:719) ~[com.kc.KnightclubbersApplication:na]
        at org.geolatte.geom.codec.Wkb.createInstance(Wkb.java:222) ~[na:na]
        ... 64 common frames omitted
Caused by: java.lang.NoSuchMethodException: org.geolatte.geom.codec.PostgisWkbDecoder.<init>()
        at [email protected]/java.lang.Class.checkMethod(DynamicHub.java:1078) ~[com.kc.KnightclubbersApplication:na]
        at [email protected]/java.lang.Class.getConstructor0(DynamicHub.java:1241) ~[com.kc.KnightclubbersApplication:na]
        at [email protected]/java.lang.Class.newInstance(DynamicHub.java:706) ~[com.kc.KnightclubbersApplication:na]
        ... 65 common frames omitted

Error 3

Caused by: java.lang.IllegalStateException: Can't find spatial_ref_sys definitions.
        at org.geolatte.geom.crs.CrsRegistry.createReader(CrsRegistry.java:80) ~

I followed the indication given here: #233 (comment) which solves some problems, but not theses ones.

System Info

OS: Windows 11
GraalVM Version 22
Java Version Java 21 CE
Plugin version: graalvm-reachability-metadata-0.10.2-repository.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions