4

I was trying to save data into the PostgreSQL through Hibernate but whenever I try to save "Location" field of "Geometry" data type, it gives me

ERROR: Invalid endian flag value encountered.

This error arises only when I'm trying to set Location of Geometry type. If I comment the line tempStudent.setLocation((Point) geom), the record is successfully saved into database. I am not able to understand where I'm getting wrong in saving the Location.

The SQL statement executed by my code:

 insert into student (email, first_name, last_name, location) values ($1, $2, $3, $4)

The parameter values:

binding parameter [1] as [VARCHAR] - [abc@gmail.com]
binding parameter [2] as [VARCHAR] - [abc1]
binding parameter [3] as [VARCHAR] - [abc2]
binding parameter [4] as [VARBINARY] - [POINT (7 2)]

The solution suggested in PostGIS Geometry saving: "Invalid endian flag value encountered." isn't working for me maybe because I'm using newer versions compared to the ones specified in that post. The versions I am using are:

  • spring-5.0.8
  • hibernate-c3p0-5.4.2
  • hibernate-spatial-5.4.2
  • jts-1.13
  • PostgreSQL 10
  • PostGIS Bundle 2.5.2

Student.java

package com.luv2code.hibernate.demo.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;

@Entity
@Table(name="student")
public class Student implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Column(name="email")
    private String email;

    @Column (name="location", columnDefinition="geometry(Point,4326)", nullable=true)
    private Point location;

    public Student() {

    }

    public Student(String firstName, String lastName, String email, int id, Point location) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.id = id;
        this.location = location;
    }

    public Point getLocation() {
        return location;
    }

    public void setLocation(Point location) {
        this.location = location;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email
                + ", location=" + location + "]";
    }

}

CreateStudentDemo.java

package com.luv2code.hibernate.demo;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.luv2code.hibernate.demo.entity.Student;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

public class CreateStudentDemo {

    public static void main(String[] args) {
        CreateStudentDemo mgr = new CreateStudentDemo();
        if(args[0].equals("store")) {
            mgr.storeLocation(assemble(args));
        }
    }

    private void storeLocation(String wktPoint) {
        WKTReader fromText = new WKTReader();
        Geometry geom = null;
        try {
            geom = fromText.read(wktPoint);
        } catch (ParseException e) {
            throw new RuntimeException("Not a WKT string: "+wktPoint);
        }
        if (!geom.getGeometryType().equals("Point")) {
            throw new RuntimeException("Geometry must be a point. Got a " + geom.getGeometryType());
        }

        // create session factory
        SessionFactory factory = new Configuration()
                                .configure("hibernate.cfg.xml")
                                .addAnnotatedClass(Student.class)
                                .buildSessionFactory();

        // create session
        Session session = factory.getCurrentSession();
        try {           
            // create a student object
            System.out.println("Creating new student object...");
        }
        catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        // start a transaction
        session.beginTransaction();

        // Student tempStudent = new Student("Paul1", "Doe1", "paul@luv2code.com", 5, (Point)geom);

        Student tempStudent = new Student();
        tempStudent.setEmail("abc@sac.in");
        tempStudent.setFirstName("Paul1");
        tempStudent.setLastName("Doel1");
        tempStudent.setLocation((Point) geom);

        /*GeometryFactory geometryFactory = new GeometryFactory();
        Point point = geometryFactory.createPoint(new Coordinate(10,7));
        tempStudent.setLocation(point);*/

        System.out.println(tempStudent.toString());
        System.out.println("Saving the student...");

        session.save(tempStudent);
        System.out.println("Done!");

        // commit transaction
        session.getTransaction().commit();
        factory.close();
    }

    private static String assemble(String[] args) {
        // TODO Auto-generated method stub
        StringBuilder builder = new StringBuilder();
        for(int i=1; i<args.length; i++) {
            builder.append(args[i]).append(" ");
        }
        return builder.toString();
    }
}

Hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- JDBC Database connection settings -->
        <property name="connection.driver_class">org.postgresql.Driver</property>
        <property name="connection.url">jdbc:postgresql://localhost:5433/ats</property>
        <property name="connection.username">postgres</property>
        <property name="connection.password">shivam</property>

        <!-- JDBC connection pool settings ... using built-in test pool -->
        <property name="connection.pool_size">1</property>

        <!-- Select our SQL dialect -->
        <property name="dialect">org.hibernate.spatial.dialect.postgis.PostgisDialect</property>

        <!-- Echo the SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Set the current session context -->
        <property name="current_session_context_class">thread</property>

    </session-factory>

</hibernate-configuration>

Error trace:

INFO: HHH000400: Using dialect: org.hibernate.spatial.dialect.postgis.PostgisDialect Creating new student object...

Student [id=0, firstName=Paul1, lastName=Doel1, email=abc@sac.in, location=POINT (7 2)]
Saving the student...
Hibernate: insert into student (email, first_name, last_name, location) values (?, ?, ?, ?)
Jul 15, 2019 10:04:08 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 0, SQLState: XX000
Jul 15, 2019 10:04:08 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: ERROR: Invalid endian flag value encountered.
Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
    at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3079)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3673)
    at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645)
    at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282)
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263)
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317)
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:332)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:289)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:196)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:127)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
    at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
    at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:713)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:705)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:700)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:350)
    at com.sun.proxy.$Proxy33.save(Unknown Source)
    at com.luv2code.hibernate.demo.CreateStudentDemo.storeLocation(CreateStudentDemo.java:69)
    at com.luv2code.hibernate.demo.CreateStudentDemo.main(CreateStudentDemo.java:19)
Caused by: org.postgresql.util.PSQLException: ERROR: Invalid endian flag value encountered.
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2468)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2211)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:309)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:446)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:370)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:149)
    at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:124)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:384)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
    ... 29 more
Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263

1 Answers1

2

I don't know why Hibernate sends the string POINT (7 2) as VARBINARY, but that is the source of your problem.

If the input is binary, PostGIS expects the geometry to be in the “Extended Well-Known Binary” (EWKB) format, and it fails to parse it, since your data are actually in “Well-Known Text” (WKT) format.

I don't know enough about Hibernate to tell if that is a bug in Hibernate or in your code, but if you manage to get Hibernate to send the point as a VARCHAR, it should work as expected.

Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
  • I noticed this is the accepted answer. Were you able to follow Laurenz' advice? How did you do it? – Mon Jul 19 '23 at 03:21