After a lot of looking around and tons of false starts I've finally hit upon the ability to work with SDO_GEOMETRY Oracle spatial types. I can convert them within the Hibernate EJB3 framework to JGeometry Java types by using a org.hibernate.usertypes.UserType implementation and specialized Dialect.
I've also added in some helper functionality to do JGeometry.equals comparisons.
- Step1 - Specify the OracleSpatialDialect as the hibernate.dialect in your Hibernate configuration.
- Step2 - If using the reverse engineering be sure to specify your table.column type as JGeometryType
Code
Example Hibernate Reverse Engineering File
<hibernate-reverse-engineering> <table-filter match-name="TIDGET_HEADER" /> <table-filter match-name="TIDGET_DATA" /> <table-filter match-name="TIDGET_DEVICE" /> <table-filter match-name="GATEWAY_DATA" /> <table-filter match-name="GATEWAY_ID" /> <table-filter match-name="TIDGET_TIME" /> <table name="GATEWAY_ID"> <column name="GATEWAY_POSITION" type="com.navsys.spatial.JGeometryType" exclude="false"/> </table> </hibernate-reverse-engineering>
Custom UserType for wrapping JGeometry
package com.navsys.spatial;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import oracle.jdbc.driver.OracleConnection;
import oracle.spatial.geometry.JGeometry;
import oracle.sql.STRUCT;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
/**
* This object is a UserType that represents an SDO_GEOMETRY type for use with
* Oracle 10g databases and the Oracle Spatial Libraries
*
* It represents an SDO_GEOMETRY database type by wrapping the
* oracle.spatial.geometry.JGeometry type and implementing
* org.hibernate.usertype.UserType.
*
* This class should be used with the OracleSpacialDialect class.
*
* (NOTE: I tried just extending the JGeometry instead of aggregating it, that
* doesn't work. The static load returns a JGeometry that can't be cast to the
* sub-class)
*
* @author Joel Schuster - The NAVSYS Corporation
* @version 1.0
* @see com.navsys.spatial.OracleSpacialDialect
*
*/
public class JGeometryType implements UserType, Serializable {
private static final long serialVersionUID = 1L;
private JGeometry geometryInstance = null;
/**
* This default constructor does create an instance of 1 point at origin
*/
public JGeometryType() {
geometryInstance = new JGeometry( 0, 0, 0);
}
public JGeometryType( JGeometry geometryInstance) {
this.geometryInstance = geometryInstance;
}
public JGeometryType( JGeometryType geometryType) {
this.geometryInstance = geometryType.getJGeometry();
}
/* User Type Information */
/*
* Note that the type that is reported is OTHER (1111) not STRUCT (2002),
* see: org.hibernate.dialect.Dialect
*/
private static final int[] SQL_TYPES = { Types.OTHER };
public int[] sqlTypes() {
return SQL_TYPES;
}
public Class returnedClass() {
return JGeometryType.class;
}
/**
* This method gives back the equals functionality that was deprecated by
* using the equals that's needed for the UserType
*/
@Override
public boolean equals( Object arg0) {
return equals( this, arg0);
}
public boolean equals( Object obj1, Object obj2) throws HibernateException {
/* check we are dealing with non-null objects of the correct type */
if( obj1 instanceof JGeometryType && obj2 instanceof JGeometryType && obj1 != null && obj2 != null) {
JGeometry geo1 = ( (JGeometryType) obj1).getJGeometry();
JGeometry geo2 = ( (JGeometryType) obj2).getJGeometry();
/* check that they are the same type */
if( geo1.getType() != geo2.getType()) {
return false;
}
/* go through the different types and check for equality */
switch( geo1.getType()) {
case JGeometry.GTYPE_POINT: {
try {
return geo1.getJavaPoint().equals( geo2.getJavaPoint());
} catch( NullPointerException npe) {
/*
* one of the points is null, this is different type
* than the reported
*/
return false;
}
}
case JGeometry.GTYPE_MULTIPOINT: {
try {
return Arrays.equals( geo1.getJavaPoints(), geo1.getJavaPoints());
} catch( NullPointerException npe) {
/*
* one of the points arrays is null, this is different
* type than the reported
*/
return false;
}
}
/*
* For lack of a better way of doing comparisons right
* now... Feel free to implement better comparisons
*/
case JGeometry.GTYPE_MULTICURVE:
case JGeometry.GTYPE_MULTIPOLYGON:
case JGeometry.GTYPE_POLYGON:
case JGeometry.GTYPE_CURVE: {
return Arrays.equals( geo1.getOrdinatesOfElements(), geo2.getOrdinatesOfElements());
}
default: {
return false;
}
}
} else {
return false;
}
}
public int hashCode( Object o) throws HibernateException {
return ( (JGeometryType) o).hashCode();
}
/* calls the load method */
public Object nullSafeGet( ResultSet resultSet, String[] strings, Object o) throws HibernateException, SQLException {
STRUCT geometry = (STRUCT) resultSet.getObject( strings[0]);
JGeometry jg = JGeometry.load( geometry);
return resultSet.wasNull() ? null : new JGeometryType( jg);
}
/* calls the store method */
public void nullSafeSet( PreparedStatement preparedStatement, Object o, int i) throws HibernateException, SQLException {
if( o == null) {
preparedStatement.setNull( i, Types.OTHER);
} else {
if( o instanceof JGeometryType) {
OracleConnection oc = (OracleConnection) preparedStatement.getConnection();
STRUCT struct = JGeometry.store( (JGeometry) ( (JGeometryType) o).getJGeometry(), oc);
preparedStatement.setObject( i, struct);
}
}
}
/* uses the 'copy' constructor */
public Object deepCopy( Object o) throws HibernateException {
if( o == null)
return null;
if( o instanceof JGeometryType) {
return new JGeometryType( ( (JGeometryType) o).getJGeometry());
} else {
return null;
}
}
public boolean isMutable() {
return false;
}
public Serializable disassemble( Object o) throws HibernateException {
return (Serializable) deepCopy( o);
}
public Object assemble( Serializable serializable, Object o) throws HibernateException {
return deepCopy( serializable);
}
public Object replace( Object o, Object o1, Object o2) throws HibernateException {
return (JGeometryType) o;
}
/* accessor */
public JGeometry getJGeometry() {
return geometryInstance;
}
/*
* Helpers so you don't have to work directly with JGeometry if you don't
* want Add to these as needed
*/
/* JGeometry Constructors */
public JGeometryType( double minX, double minY, double maxX, double maxY, int srid) {
geometryInstance = new JGeometry( minX, minY, maxX, maxY, srid);
}
public JGeometryType( double x, double y, double z, int srid) {
geometryInstance = new JGeometry( x, y, z, srid);
}
public JGeometryType( double x, double y, int srid) {
geometryInstance = new JGeometry( x, y, srid);
}
public JGeometryType( int gtype, int srid, double x, double y, double z, int[] elemInfo, double[] ordinates) {
geometryInstance = new JGeometry( gtype, srid, x, y, z, elemInfo, ordinates);
}
public JGeometryType( int gtype, int srid, int[] elemInfo, double[] ordinates) {
geometryInstance = new JGeometry( gtype, srid, elemInfo, ordinates);
}
static public JGeometryType createCircle( double x1, double y1, double x2, double y2, double x3, double y3, int srid) {
return new JGeometryType( JGeometry.createCircle( x1, y1, x2, y2, x3, y3, srid));
}
static public JGeometryType createCircle( double x, double y, double radius, int srid) {
return new JGeometryType( JGeometry.createCircle( x, y, radius, srid));
}
static public JGeometryType createLinearLineString( double[] coords, int dim, int srid) {
return new JGeometryType( JGeometry.createLinearLineString( coords, dim, srid));
}
static public JGeometryType createLinearMultiLineString( Object[] coords, int dim, int srid) {
return new JGeometryType( JGeometry.createLinearMultiLineString( coords, dim, srid));
}
static public JGeometryType createLinearPolygon( double[] coords, int dim, int srid) {
return new JGeometryType( JGeometry.createLinearPolygon( coords, dim, srid));
}
static public JGeometryType createLinearPolygon( Object[] coords, int dim, int srid) {
return new JGeometryType( JGeometry.createLinearPolygon( coords, dim, srid));
}
static public JGeometryType createMultiPoint( Object[] coords, int dim, int srid) {
return new JGeometryType( JGeometry.createMultiPoint( coords, dim, srid));
}
static public JGeometryType createPoint( double[] coord, int dim, int srid) {
return new JGeometryType( JGeometry.createPoint( coord, dim, srid));
}
/* not really overrides, but helpers */
static public double[] computeArc( double x1, double y1, double x2, double y2, double x3, double y3) {
return JGeometry.computeArc( x1, y1, x2, y2, x3, y3);
}
public java.awt.Shape createShape() {
return geometryInstance.createShape();
}
public int getDimensions() {
return geometryInstance.getDimensions();
}
public int[] getElemInfo() {
return geometryInstance.getElemInfo();
}
public double[] getFirstPoint() {
return geometryInstance.getFirstPoint();
}
public java.awt.geom.Point2D getJavaPoint() {
return geometryInstance.getJavaPoint();
}
public java.awt.geom.Point2D[] getJavaPoints() {
return geometryInstance.getJavaPoints();
}
public java.awt.geom.Point2D getLabelPoint() {
return geometryInstance.getLabelPoint();
}
public double[] getLastPoint() {
return geometryInstance.getLastPoint();
}
public double[] getMBR() {
return geometryInstance.getMBR();
}
public int getNumPoints() {
return geometryInstance.getNumPoints();
}
public double[] getOrdinatesArray() {
return geometryInstance.getOrdinatesArray();
}
public Object[] getOrdinatesOfElements() {
return geometryInstance.getOrdinatesOfElements();
}
public double[] getPoint() {
return geometryInstance.getPoint();
}
public long getSize() {
return geometryInstance.getSize();
}
public int getSRID() {
return geometryInstance.getSRID();
}
public int getType() {
return geometryInstance.getType();
}
public boolean hasCircularArcs() {
return geometryInstance.hasCircularArcs();
}
public boolean isCircle() {
return geometryInstance.isCircle();
}
public boolean isGeodeticMBR() {
return geometryInstance.isGeodeticMBR();
}
public boolean isLRSGeometry() {
return geometryInstance.isLRSGeometry();
}
public boolean isMultiPoint() {
return geometryInstance.isMultiPoint();
}
public boolean isPoint() {
return geometryInstance.isPoint();
}
public boolean isRectangle() {
return geometryInstance.isRectangle();
}
public static double[] linearizeArc( double x1, double y1, double x2, double y2, double x3, double y3) {
return JGeometry.linearizeArc( x1, y1, x2, y2, x3, y3);
}
public static double[] linearizeArc( double x1, double y1, double x2, double y2, double x3, double y3, double tolerance) {
return JGeometry.linearizeArc( x1, y1, x2, y2, x3, y3, tolerance);
}
public static double[] linearizeArc( double x1, double y1, double x2, double y2, double x3, double y3, int numPoints) {
return JGeometry.linearizeArc( x1, y1, x2, y2, x3, y3, numPoints);
}
public void setSRID( int srid) {
geometryInstance.setSRID( srid);
}
public void setType( int gt) {
geometryInstance.setType( gt);
}
}
Custom Dialect for specifying SDO_GEOMETRY
package com.navsys.spatial;
import java.sql.Types;
import org.hibernate.dialect.Oracle9Dialect;
/**
* This class extends the Oracle9Dialect for Hibernate by adding the
* sdo_geometry type as an sql.OTHER type.
*
* @author Joel Schuster - The NAVSYS Corporation
* @version 1.0
* @see com.navsys.spatial.OracleSpacialDialect
*
*/
public class OracleSpatialDialect extends Oracle9Dialect {
public OracleSpatialDialect() {
super();
registerColumnType( Types.OTHER, "sdo_geometry");
}
}
Questions?
mailto:guurk (at) plasmapowered (dot) com
or
mailto:joels (at) navsys (dot) com
Enjoy.
Comments