Oracle Spatial Datatype JGeometry from the spatial api (which can be found here) can easily be used with hibernate through a custom dialect and a custom type that delegates to an instance from oracle sdo api. Everything that is needed is here:
Mapping Spatial Oracle type SDO_GEOMETRY to JGeometry
The only quirk with this solution as of February 2007 is the fact, it won’t work with null columns. The fault lies in nullSafeSet. Either can the JGeometry delegate be null or, what is worse, preparedStatement.setNull( i, Types.OTHER); will fail with an invalid column type. The correct version of this method is as follows:
public void nullSafeSet( PreparedStatement preparedStatement, Object o, int i) throws HibernateException, SQLException { if( o == null) { preparedStatement.setNull(i, Types.STRUCT, "MDSYS.SDO_GEOMETRY"); } else { if( o instanceof JGeometryType) { JGeometryType gt = (JGeometryType) o; OracleConnection oc = (OracleConnection) preparedStatement.getConnection().getMetaData().getConnection(); if(gt.getJGeometry() == null) preparedStatement.setNull(i, Types.STRUCT, "MDSYS.SDO_GEOMETRY"); else preparedStatement.setObject( i, JGeometry.store( (JGeometry) (gt).getJGeometry(), oc)); } } }
Furthermore, i think the spatial dialect should be registered with the following class:
public class OracleSpatialDialect extends Oracle9Dialect { public OracleSpatialDialect() { super(); registerColumnType( Types.OTHER, "MDSYS.SDO_GEOMETRY"); } }
Kudos to Joel Schuster from Navisys for the adapter class!
17 Comments
Hallo!
Kannst Du mir vielleicht verraten welches Plugin Du nutzt, um Java Code zu posten? Sieht sehr nett aus mit dem Syntax Hilighting.
Danke!
Hi Philip,
Das Plugin heisst “Code Snippet”
http://blog.enargi.com/codesnippet/
Der Link ist leider tot.
Vielleicht kannst Du ja mal das folgende Plugin einbauen:
http://txfx.net/code/wordpress.....-comments/
Dann dann man per Mail benachrichtigt werden wenn Du oder jemand anders antwortet.
Danke!
Also would like to add that the line:
OracleConnection oc = (OracleConnection) preparedStatement.getConnection();
fails if using container managed datasources.
The solutions is to use:
…preparedStatement.getConnection().getMetaData().getConnection();
Thank you J-P, you’re right!
Ich verwende Hibernate JPA innerhalb eines JBoss Seam Projektes und stoße bei der Verwendung des JGeometryTypes immer wieder auf folgende Exception:
org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.efkon.fleettracking.datamodel.TripPoints.point
Mein TripPoints Entity sieht dabei folgendermaßen aus:
Natürlich habe ich überall Setter und Getter dazu generiert.
Kann mir jemand von euch dabei helfen?
Mit bestem Dank,
thomas
Hallo Thomas,
könnte es daran liegen, das der Typ des Members nicht mit Typ der Spalte übereinstimmt?
@Type(type=”com.navsys.spatial.JGeometryType”) ist korrekt, aber der Member ist vom Type oracle.spatial.geometry.JGeometry.
Hibernate findet dann die Getter / Setter nicht.
Wenn es etwas JPA spezifisches, kann ich Dir leider nicht helfen, da ich kein JPA nutze.
Hallo Michael,
danke für die schnelle Antwort! Das könnte es glaube ich sein! Ich werde es gleich ausprobieren. Hab enämlich gerade bei genauerer Betrachtung des Codes festgestellt, dass die gesamte JGeometry-Funktionalität innerhalb de UserTypes nochmals abgebildet ist.
Ich melde mich nach dem Test wieder bei dir.
Vielen Dank,
Thomas
Ja, ich sehe gerade, dass im Code von Herrn Schuster folgendes Konstrukt definiert ist:
public Class returnedClass() {
return JGeometryType.class;
}
Somit war meine Implementierung falsch! Ich hatte schon in anderen Projekten UserTypes definiert, die bisher aber nie sich selbst zurückgegeben haben, sondern immer einen entsprechenden Java-Typ (z.B.: java.util.Date bei der Implementierung von Zeitzonenlogik innerhalb eines Userdefined Types oder einen java.Math.BigDecimal bei der Implementierung eines MonetaryAmount User-Types). Dadurch fallen bei der Verwendung des zurückgegebenen Typs die für die Businesslogik nicht notwendigen Methodne weg (z.B.: nullSafeGet(), nullSafeSet usw.)
Betsen Dank nochmals,
Thomas
Hi Michael,
ja, das war das Problem! Auch einfach an folgendem Code-Konstrukt zu erkennen:
public Class returnedClass() {
return JGeometryType.class;
}
Bisher hatte ich das nicht so genau beachtet und bei eigenen UserType-Implementierungen immer einen primitiven Typ zurückgegeben.
Aber so funktioniert es auch! Obwohl ich Methodne wie nullSafeSet() und nullSafeSet() innerhalb meiner Businesslogik eigentlich verbergen möchte…
Mit bestem Dank,
Thomas
Hey Thomas,
freut mich, dass ich Dir helfen konnte.
Viele Grüße aus Aachen,
Michael
Hallo Michael,
ich habe JGeometry auch shcon innerhalb eines Toplink JPA Projektes verwendet. Innerhalb dieses Projektes war es mir möglich über sog. SessionCustomizer NamedQueries zu definieren, die mir Datenbankseitig eine “FindNearestNeighbour”-Funktion auf meine Geodaten ausführen.
Weißt du zufällig ob es innerhalb von Hibernate JPA auch möglich ist die Standardoperatoren um Spatial-Operatoren zu erweitern (WithinDistance, FindNN, NN, NN_Distance…) und dies edann innerhalb von NamedQueries zu verwenden?
Mit bestem Dank,
Thomas
Ich hab Named Queries in den Hibernate hbm.xml hinterlegt und dort kannst Du arbiträre Datenbankfunktionen aufrufen, das wie gesagt habe ich aber nur ohne den JPA Layer gemacht.
z.B. um Elemente innerhalb eines Planes abzurufen:
Die kannst Du dann z.B. wie folgt abrufen:
plan.getRahmen() ist vom Typ JGeometryType.
Alternativ habe ich an einigen Stellen auch die Hibernate QL wie folgt genutzt:
Ich weiß nicht, was Du für eine DB verwendest, aber in meinen Beispielen handelt es sich um Oracle Spatial Data Option Operatoren. Wenn Du Dir eigene Methoden baust, sollte das analog funktionieren.
Darf ich fragen, wie Du eigentlich auf mein Blog gestoßen bist? Kannst mich auch gerne weiter empfehlen
Grüße und viel Erfolg,
Michael.
Hi Michael,
Thanks for the blog,
I have a problem and unfortunately I don’t speak german.
It is maybe the same problem as above.
In my xml mapping file, I have:
and in the associated hibernate entity :
private JGeometry geom;
public JGeometry getGeom() {
return this.geom;
}
public void setGeom(JGeometry geom) {
this.geom = geom;
}
When I try to load this entity, I get the following exception:
BasicPropertyAccessor: IllegalArgumentException in class: be.pulsar.xnotam.model.Navaid, setter method of property: geom
BasicPropertyAccessor: expected type: oracle.spatial.geometry.JGeometry, actual value: com.navsys.spatial.JGeometryType
Thanks in advance!
Jim
The xml was (there was a problem in my post above)
<property name=”geom” type=”com.navsys.spatial.JGeometryType”>
<column name=”GEOM” />
</property>
Hey Jim,
assuming your member “geom” is a oracle.spatial.geometry.JGeometry, the xml declaration is wrong and the problem is the same as above.
What you wanna do with the hibernate code i linked in my original post is:
Define a custom type for mapping oracle spatial named “com.navsys.spatial.JGeometryType”.
Then you wanna use this type in your own hibernate mappings.
So i guess you wanted the member “geom” to be a “com.navsys.spatial.JGeometryType” and not a “oracle.spatial.geometry.JGeometry”. If you change its type and the accessor accordingly, the no setter / getter errors will disappear.
Cheers,
Michael.
Post a Comment