[postgis-users] Hibernate and Postgis

rpardo at sevilla.idom.es rpardo at sevilla.idom.es
Tue Jul 11 10:01:09 PDT 2006


Hello, i'm newbie with postgis and
I'm trying to make an hibernate custom type for geometry jts based on the
classes
http://lists.jump-project.org/pipermail/jts-devel/2005-October/001310.html
It doesn't work properly because a parse problem: invalid geometry
I think that the problem is a bad use  of the  objects WKBReadear and
WKBWriter or also a
bad hibernate configuration ..
does anybody know what could be the problem?

thanks a lot


My hibernate configuration is
<property name="pto" type="com.idom.jex.cc.utils.GeometryUserType" >
  <column name="userobject" sql-type="geometry"/>
</property>

package com.idom.jex.cc.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.UnhandledException;
import org.hibernate.HibernateException;
import org.hibernate.usertype.EnhancedUserType;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ByteOrderValues;
import com.vividsolutions.jts.io.InputStreamInStream;
import com.vividsolutions.jts.io.OutputStreamOutStream;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKBReader;
import com.vividsolutions.jts.io.WKBWriter;

public class GeometryUserType implements EnhancedUserType {

  /**
   * Return the SQL type codes for the columns mapped by this type. The
codes
   * are defined on <tt>java.sql.Types</tt>.
   *
   * @see java.sql.Types
   * @return int[] the typecodes
   */
  public int[] sqlTypes() {
    return new int[] { Types.BLOB };
  }

  /**
   * The class returned by <tt>nullSafeGet()</tt>.
   *
   * @return Class
   */
  public Class returnedClass() {
    return Geometry.class;
  }

  /**
   * Compare two instances of the class mapped by this type for persistence
   * "equality". Equality of the persistent state.
   *
   * @param x
   * @param y
   * @return boolean
   */
  public boolean equals(Object x, Object y) throws HibernateException {
    return x == y;
  }

  /**
   * Get a hashcode for the instance, consistent with persistence
"equality"
   */
  public int hashCode(Object x) throws HibernateException {
    return x.hashCode();
  }

  /**
   * Retrieve an instance of the mapped class from a JDBC resultset.
   * Implementors should handle possibility of null values.
   *
   * @param rs a JDBC result set
   * @param names the column names
   * @param owner the containing entity
   * @return Object
   * @throws HibernateException
   * @throws SQLException
   */
  @SuppressWarnings("deprecation")
  public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
    throws HibernateException, SQLException
  {
    try {
      InputStream is = rs.getBinaryStream(names[0]);

      if(is == null)
        return null;

      byte [] buf = new byte[4];
      is.read(buf);

      int SRID = ByteOrderValues.getInt(buf,
ByteOrderValues.LITTLE_ENDIAN);

      WKBReader reader = new WKBReader();

      Geometry ret = reader.read(new InputStreamInStream(is));
      ret.setSRID(SRID);

      return ret;
    }
    catch (ParseException e) {
      throw new IllegalStateException(e);
    }
    catch (IOException e) {
      throw new UnhandledException(e);
    }
  }

  /**
   * Write an instance of the mapped class to a prepared statement.
Implementors
   * should handle possibility of null values. A multi-column type should
be
   * written to parameters starting from <tt>index</tt>.
   *
   * @param st a JDBC prepared statement
   * @param value the object to write
   * @param index statement parameter index
   * @throws HibernateException
   * @throws SQLException
   */
  @SuppressWarnings("deprecation")
  public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException,
      SQLException {
    if (value == null) {
      st.setNull(index, Types.BLOB);
    }
    else {
      Geometry geom = (Geometry)value;

      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      int SRID = geom.getSRID();

      try {
        byte [] buf = new byte[4];
        ByteOrderValues.putInt(SRID, buf, ByteOrderValues.LITTLE_ENDIAN);
        bos.write(buf);

        WKBWriter writer = new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN);
        writer.write(geom, new OutputStreamOutStream(bos));
      }
      catch (IOException e) {
        // should be impossible
        throw new UnhandledException(e);
      }

      st.setBytes(index, bos.toByteArray());
    }
  }

  /**
   * Return a deep copy of the persistent state, stopping at entities and
at
   * collections. It is not necessary to copy immutable objects, or null
values,
   * in which case it is safe to simply return the argument.
   *
   * @param value the object to be cloned, which may be null
   * @return Object a copy
   */
  public Object deepCopy(Object value) throws HibernateException {
    return value;
  }

  /**
   * Are objects of this type mutable?
   *
   * @return boolean
   */
  public boolean isMutable() {
    return false;
  }

  /**
   * Transform the object into its cacheable representation. At the very
least
   * this method should perform a deep copy if the type is mutable. That
may not
   * be enough for some implementations, however; for example, associations
must
   * be cached as identifier values. (optional operation)
   *
   * @param value the object to be cached
   * @return a cachable representation of the object
   * @throws HibernateException
   */
  public Serializable disassemble(Object value) throws HibernateException {
    return (Geometry)value;
  }

  /**
   * Reconstruct an object from the cacheable representation. At the very
least
   * this method should perform a deep copy if the type is mutable.
(optional
   * operation)
   *
   * @param cached the object to be cached
   * @param owner the owner of the cached object
   * @return a reconstructed object from the cachable representation
   * @throws HibernateException
   */
  public Object assemble(Serializable cached, Object owner) throws
HibernateException {
    return (Geometry)cached;
  }

  /**
   * During merge, replace the existing (target) value in the entity we are
   * merging to with a new (original) value from the detached entity we are
   * merging. For immutable objects, or null values, it is safe to simply
return
   * the first parameter. For mutable objects, it is safe to return a copy
of
   * the first parameter. For objects with component values, it might make
sense
   * to recursively replace component values.
   *
   * @param original the value from the detached entity being merged
   * @param target the value in the managed entity
   * @return the value to be merged
   */
  public Object replace(Object original, Object target, Object owner)
throws HibernateException {
    return original;
  }

  // enhanced methods

  @SuppressWarnings("deprecation")
  public String objectToSQLString(Object value) {
    Geometry geom = (Geometry)value;
    return "GeomFromText(" + geom.toText() + ", " + geom.getSRID() + ")";
  }

  public String toXMLString(Object value) {
    return objectToSQLString(value);
  }

  public Object fromXMLString(String xmlValue) {
    throw new NotImplementedException("Currently not implemented");
  }

}

the hibernate error
Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch
update
      at
org.hibernate.exception.SQLStateConverter.handledNonSpecificException(
SQLStateConverter.java:82)
      at org.hibernate.exception.SQLStateConverter.convert(
SQLStateConverter.java:70)
      at org.hibernate.exception.JDBCExceptionHelper.convert(
JDBCExceptionHelper.java:43)
      at org.hibernate.jdbc.AbstractBatcher.executeBatch(
AbstractBatcher.java:179)
      at org.hibernate.engine.ActionQueue.executeActions(
ActionQueue.java:226)
      at org.hibernate.engine.ActionQueue.executeActions(
ActionQueue.java:136)
      at
org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(
AbstractFlushingEventListener.java:274)
      at org.hibernate.event.def.DefaultFlushEventListener.onFlush(
DefaultFlushEventListener.java:27)
      at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:716)
      at com.idom.utils.IdomSession.commitTransaction(IdomSession.java:95)
      at com.idom.utils.Context.PersistenceContext.commitTransaction(
PersistenceContext.java:52)
      at com.idom.jex.cc.servicios.DAO.CoordenadaDAO.main(
CoordenadaDAO.java:31)
Caused by: Batch entry 0 insert into INVENTARIOSIG.INVS_COORDENADA (PUNTO_,
X_, Y_, Z_, userobject, ID_) values ( was aborted. Call getNextException()
to see the cause.
      at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(
AbstractJdbc2Statement.java:107)
      at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(
BatchingBatcher.java:57)
      at org.hibernate.jdbc.AbstractBatcher.executeBatch(
AbstractBatcher.java:172)
      ... 8 more



Rubén Pardo López
Ingeniero en Informática

IDOM Servicios Integrales de Ingeniería, S.L.
C/ Exposición, 14 -1ª planta (PISA)
41923 - Mairena del Aljarafe - SEVILLA
tlf: 955 600 528   fax: 955 600 488
rpardo at sevilla.idom.es
www.idom.es





More information about the postgis-users mailing list