8

Related to previous question. I have a Spring Roo application using Hibernate to write a Geometry object to a PostGIS database using JTS. I believe I've fixed the problems I had in defining my Geometry object, and now Hibernate is executing its persist() method, but something is going wrong just before it hits the DB and I'm getting the exception below.

Here are some interesting lines. First from the Hibernate logs, the object to be persisted, and then an SQL query (presumably the ? are substituted):

...
DEBUG org.hibernate.pretty.Printer - com.test.LandUse{id=1, centerPoint=POINT (5 6), version=0}
...
DEBUG org.hibernate.SQL - insert into land_use (center_point, version, id) values (?, ?, ?)
...

Then some more things happen, though nothing obviously bad. However I don't see any 'final' SQL, and there is an attempt to roll back the transaction. Then:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspect$3$2a73e96c(AbstractTransactionAspect.aj:78)
    at com.test.LandUse_Roo_Jpa_ActiveRecord.ajc$interMethod$com_test_LandUse_Roo_Jpa_ActiveRecord$com_test_LandUse$persist(LandUse_Roo_Jpa_ActiveRecord.aj:44)
    at com.test.LandUse.persist(LandUse.java:1)
    at com.test.LandUse_Roo_Jpa_ActiveRecord.ajc$interMethodDispatch1$com_test_LandUse_Roo_Jpa_ActiveRecord$com_test_LandUse$persist(LandUse_Roo_Jpa_ActiveRecord.aj)
    at com.test.LandUseController_Roo_Controller.ajc$interMethod$com_test_LandUseController_Roo_Controller$com_test_LandUseController$create(LandUseController_Roo_Controller.aj:29)
    at com.test.LandUseController.create(LandUseController.java:1)
...
Caused by: javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512)
    ... 54 more
Caused by: java.lang.UnsupportedOperationException
    at org.hibernate.spatial.GeometrySqlTypeDescriptor.getBinder(GeometrySqlTypeDescriptor.java:52)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:283)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:278)
    at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:89)
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2184)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2430)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)
    at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
    ... 55 more

I've been trying to get this simple use case (an object with just a single Geometry property) working for over a week now, and am about at my wits' end. If I replace the Geometry object with a String it works just fine. Does anyone know what might be causing such an error?

EDIT: Thierry's answer below got me poking through the source, and I noticed the exception is thrown in GeometrySqlTypeDescriptor, which has some interesting contents:

/**
 * A generic <code>SqlTypeDescriptor</code>, intended to be remapped
 * by the spatial dialect.
 *
 * @author Karel Maesen, Geovise BVBA
 *         creation-date: 7/27/11
 */
public class GeometrySqlTypeDescriptor implements SqlTypeDescriptor {

    public static final GeometrySqlTypeDescriptor INSTANCE = new GeometrySqlTypeDescriptor();

    @Override
    public int getSqlType() {
        return 3000; //this value doesn't conflict with presently defined java.sql.Types values.
    }

    @Override
    public boolean canBeRemapped() {
        return true;
    }

    @Override
    public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
        throw new UnsupportedOperationException();
    }

    @Override
    public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
        throw new UnsupportedOperationException();
    }
}

In particular, note the class comment suggesting something is clearly wrong with the Hibernate dialect mapping. Unfortunately I have no idea what that means, but I'm guessing due to some kind of version mismatch. (Note also the declaration of SQL type 3000, as per my previous error!)

My current dialect is org.hibernate.spatial.dialect.postgis.PostgisDialect, as per the Hibernate Spatial usage guide. I'm using Hibernate Spatial 4.0-M1, JTS 1.12, and PostGIS 2.0.1. I'll try with a couple of different versions of PostGIS perhaps, particularly since that's the one dependency that Hibernate Spatial is supposed to provide but doesn't seem to.

Community
  • 1
  • 1
orlade
  • 2,060
  • 4
  • 24
  • 35
  • 1
    I was able to remove the dependency on `postgis-jdbc` in pom.xml without complaint, so presumably Hibernate Spatial is dragging the right version of that in for me. However the problem persists (hah). – orlade Sep 02 '12 at 16:01

3 Answers3

14

It seems the problem was that the PostgisDialect was not been picked up and integrated correctly, and hence the required operations were not supported. The solution was as simple as upgrading from Hibernate 3.6.9.Final to 4.1.6.Final!

See my thread on the mailing list for more information.

As per that thread, you should also be aware that as of Hibernate Spatial 4.0-M1, only the Geometry type is specified to Hibernate, and hence the @Column annotation must set columnDefinition="Geometry", and not Point or anything else. This may be fixed in the future.

With this anthology of modifications, I can finally write a Point to a database! The correct property specification is:

@Column(columnDefinition="Geometry")
@Type(type = "org.hibernate.spatial.GeometryType")
private Point centerPoint;
orlade
  • 2,060
  • 4
  • 24
  • 35
  • 1
    Glad to know that! I think it was related to another stuff like from the [Hibernate Migration Guide 3.6](https://community.jboss.org/wiki/HibernateCoreMigrationGuide36), part 4) `If you are using Hibernate 3.6.0 with PostgreSQL, the global environment variable, hibernate.jdbc.use_streams_for_binary, must be set to false if you are using clob or blob properties. In addition, using materialized_blob and materialized_clob properties with PostgreSQL is currently broken. See HHH-4617 for details (fixed in 3.6.1)` – BendaThierry.com Sep 07 '12 at 12:21
  • For other readers at the future: the solution to cast the Point to Geometry when you print it on screen and cast the Point to Geometry before store them inside the database is a good workaround until the Postgis project handle subtypes of Geometry as proper Hibernate Types. Maybe you could do this inside a DAO layer, if any. – BendaThierry.com Sep 07 '12 at 12:32
  • This question and answer series saved my project. Thank you all so much! – Deven Phillips Nov 09 '12 at 16:23
  • 1
    Excellent! I'd hate for anyone else to have to go through all this again. – orlade Nov 10 '12 at 03:56
  • @Travis: I'm sorry to say I have no idea what to do then. I can't even remember what I did myself. I'd recommend chasing the problem on the mailing list (linked above), since those guys know their stuff. – orlade Mar 08 '13 at 20:40
  • @orlade Thanks so much for sharing the solution to this problem. I got the very same problem with Point and Geometry. But in my case when I tryid to persist it, the Database replied with a ClassCastException, that it is not able to cast org.postgis.Point to a vividsolution Point. So I use the vividsolution Point instead of the PostGIS version. Don't know why it requires now a completely different object. But I'm happy that my code works. – Brain Dec 06 '15 at 12:51
  • This is not working anymore with Hibernate 5.x since it aims avoiding the Types. – alvgarvilla May 31 '16 at 08:38
2

I got this exception when I forgot to add the Postgis Dialect in hibernate configuration file.

Add following line to hibernate.cfg.xml

<property name="dialect">org.hibernate.spatial.dialect.postgis.PostgisDialect</property>
Rajdeep Siddhapura
  • 873
  • 1
  • 7
  • 20
1

Yes, the ? are substituted by the values you need to store.

Did you try to use the following type: GeometryUserType and not the GeometryType? I suspect GeometryType is not directly supported by the API of Hibernate Spatial Project. It is maybe an abstract class which you could not instantiate directly to map your datas with annotations - it acts beyond the scene as we have experimented.

Caused by: java.lang.UnsupportedOperationException which has make me tell that.

And the last XML stuff inside the tutorial you have followed is clear:

...
<property name="geometry" type="org.hibernatespatial.GeometryUserType">
    <column name="geom" />
</property>
...

Looking at the code inside the GeometryUserType I see only one place where these exception could be thrown.

public Object conv2DBGeometry(Geometry jtsGeom, Connection connection) {
        org.postgis.Geometry geom = null;
        jtsGeom = forceEmptyToGeometryCollection(jtsGeom);
        if (jtsGeom instanceof com.vividsolutions.jts.geom.Point) {
            geom = convertJTSPoint((com.vividsolutions.jts.geom.Point) jtsGeom);
        } else if (jtsGeom instanceof com.vividsolutions.jts.geom.LineString) {
            geom = convertJTSLineString((com.vividsolutions.jts.geom.LineString) jtsGeom);
        } else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiLineString) {
            geom = convertJTSMultiLineString((com.vividsolutions.jts.geom.MultiLineString) jtsGeom);
        } else if (jtsGeom instanceof com.vividsolutions.jts.geom.Polygon) {
            geom = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) jtsGeom);
        } else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPoint) {
            geom = convertJTSMultiPoint((com.vividsolutions.jts.geom.MultiPoint) jtsGeom);
        } else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPolygon) {
            geom = convertJTSMultiPolygon((com.vividsolutions.jts.geom.MultiPolygon) jtsGeom);
        } else if (jtsGeom instanceof com.vividsolutions.jts.geom.GeometryCollection) {
            geom = convertJTSGeometryCollection((com.vividsolutions.jts.geom.GeometryCollection) jtsGeom);
        }

        if (geom != null)
            return new PGgeometry(geom);
        else
            throw new UnsupportedOperationException("Conversion of "
                    + jtsGeom.getClass().getSimpleName()
                    + " to PGgeometry not supported");
    }

Where PGgeometry stands for PostGis Geometry I think (or maybe PostgreSQL).

I have found some topics where Karel Maesen and others speak about the InnoDB support is not very well, but they are maybe outdated (05-2011).

Good luck!

BendaThierry.com
  • 2,080
  • 1
  • 15
  • 17
  • 1
    My understanding is that GeometryUserType was the correct type for Hibernate Spatial 1.0, and that it has been replaced by GeometryType Hibernate Spatial 4.0. `org.hibernate.spatial.GeometryUserType` does not exist in 4.0. The closest alternative is `org.hibernate.spatial.GeometrySqlTypeDescriptor`, but unsurprisingly that fails too. – orlade Sep 02 '12 at 15:42
  • Ok, didn't remember about these info. Good catch. – BendaThierry.com Sep 02 '12 at 15:51
  • But it does lead to some interesting points! See edited question. – orlade Sep 02 '12 at 15:51
  • 1
    I've looked at it. It seems to turn us around but solving nothing... I suggest you read help on the [official forum](http://hibernate-spatial.1140993.n2.nabble.com/) or ask help going trough their mailing list system. – BendaThierry.com Sep 02 '12 at 16:02
  • Thanks Thierry, you're a legend. I'm just hitting up the mailing list now. Perhaps my biggest weakness is always waiting too long to ask for help :). – orlade Sep 02 '12 at 16:11
  • Don't worry - it is the same for a lot of people. – BendaThierry.com Sep 02 '12 at 16:16