HHH-14523 Fix for dirty-checking bug
This commit is contained in:
parent
56e9769741
commit
bdcd1a0fb2
|
@ -26,6 +26,7 @@ dependencies {
|
|||
testCompile(libraries.junit)
|
||||
testCompile(project(':hibernate-testing'))
|
||||
testCompile([group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4'])
|
||||
testCompile( project( path: ':hibernate-core', configuration: 'tests' ) )
|
||||
testCompile(libraries.validation)
|
||||
testCompile(libraries.jandex)
|
||||
testCompile(libraries.classmate)
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.spatial;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.spatial.jts.JTSUtils;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
@ -54,6 +55,11 @@ public class JTSGeometryJavaTypeDescriptor extends AbstractTypeDescriptor<Geomet
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areEqual(Geometry one, Geometry another) {
|
||||
return JTSUtils.equalsExact3D( one, another );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X unwrap(Geometry value, Class<X> type, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
|
|
|
@ -48,4 +48,5 @@ public class JTSGeometryType extends AbstractSingleColumnStandardBasicType<Geome
|
|||
return "jts_geometry";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.spatial.jts;
|
||||
|
||||
|
||||
//Note that this Utility class will be available directly from
|
||||
// geolatte-geom 1.9
|
||||
|
||||
|
||||
import org.locationtech.jts.geom.Coordinate;
|
||||
import org.locationtech.jts.geom.Geometry;
|
||||
import org.locationtech.jts.geom.LineString;
|
||||
import org.locationtech.jts.geom.Point;
|
||||
import org.locationtech.jts.geom.Polygon;
|
||||
|
||||
/**
|
||||
* Some utility functions for working with JTS geometries
|
||||
*/
|
||||
public class JTSUtils {
|
||||
|
||||
private JTSUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines equality between geometries taking into
|
||||
* account all coordinates, and the SRID.
|
||||
* <p>
|
||||
* This is used e.g. for Dirty-checking of geometry values
|
||||
* in Hibernate
|
||||
*
|
||||
* @param g1
|
||||
* @param g2
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean equalsExact3D(Geometry g1, Geometry g2) {
|
||||
if ( g1 == g2 ) {
|
||||
return true;
|
||||
}
|
||||
if ( g1 == null || g2 == null ) {
|
||||
return false;
|
||||
}
|
||||
if ( !g1.getGeometryType().equals( g2.getGeometryType() ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( g1.getSRID() != g2.getSRID() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//empty geometries of the same type are the same
|
||||
if ( g1.isEmpty() && g2.isEmpty() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int ng1 = g1.getNumGeometries();
|
||||
int ng2 = g2.getNumGeometries();
|
||||
if ( ng1 != ng2 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ng1 == 1 ) {
|
||||
return equals3DPrimitiveGeometries( g1, g2 );
|
||||
}
|
||||
|
||||
return equalComponentGeometries( g1, g2, ng1 );
|
||||
}
|
||||
|
||||
private static boolean equalComponentGeometries(Geometry g1, Geometry g2, int ng1) {
|
||||
for ( int gIdx = 0; gIdx < ng1; gIdx++ ) {
|
||||
if ( !equalsExact3D( g1.getGeometryN( gIdx ), g2.getGeometryN( gIdx ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean equals3D(Coordinate c1, Coordinate c2) {
|
||||
return c1.x == c2.x && c1.y == c2.y &&
|
||||
( ( Double.isNaN( c1.z ) && Double.isNaN( c2.z ) ) || c1.z == c2.z ) &&
|
||||
( ( Double.isNaN( c1.getM() ) && Double.isNaN( c2.getM() ) ) || c1.getM() == c2.getM() );
|
||||
}
|
||||
|
||||
private static boolean equalLineStringCoordinates(LineString g1, LineString g2) {
|
||||
int np1 = g1.getNumPoints();
|
||||
int np2 = g2.getNumPoints();
|
||||
if ( np1 != np2 ) {
|
||||
return false;
|
||||
}
|
||||
for ( int i = 0; i < np1; i++ ) {
|
||||
if ( !equalsExact3D( g1.getPointN( i ), g2.getPointN( i ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean equalPolygonCoordinates(Polygon g1, Polygon g2) {
|
||||
int nr1 = g1.getNumInteriorRing();
|
||||
int nr2 = g2.getNumInteriorRing();
|
||||
if ( nr1 != nr2 ) {
|
||||
return false;
|
||||
}
|
||||
for ( int i = 0; i < nr1; i++ ) {
|
||||
if ( !equalLineStringCoordinates( g1.getInteriorRingN( i ), g2.getInteriorRingN( i ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return equalLineStringCoordinates( g1.getExteriorRing(), g2.getExteriorRing() );
|
||||
}
|
||||
|
||||
private static boolean equals3DPrimitiveGeometries(Geometry g1, Geometry g2) {
|
||||
//this method assumes that g1 and g2 are of the same type
|
||||
assert ( g1.getClass().equals( g2.getClass() ) );
|
||||
if ( g1 instanceof Point ) {
|
||||
return equals3D( g1.getCoordinate(), g2.getCoordinate() );
|
||||
}
|
||||
|
||||
if ( g1 instanceof LineString ) {
|
||||
return equalLineStringCoordinates( (LineString) g1, (LineString) g2 );
|
||||
}
|
||||
|
||||
if ( g1 instanceof Polygon ) {
|
||||
return equalPolygonCoordinates( (Polygon) g1, (Polygon) g2 );
|
||||
}
|
||||
throw new IllegalStateException( "Only simple geometries should be used" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.spatial.integration.jts.hhh14523;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.geolatte.geom.codec.Wkt;
|
||||
import org.geolatte.geom.jts.JTS;
|
||||
import org.locationtech.jts.geom.GeometryFactory;
|
||||
import org.locationtech.jts.geom.Point;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@TestForIssue(jiraKey = "HHH-14523")
|
||||
@RequiresDialect(PostgisPG95Dialect.class)
|
||||
public class DirtyCheckingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private GeometryFactory gfact = new GeometryFactory();
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
TestEntity.class
|
||||
};
|
||||
}
|
||||
|
||||
public void createtestEntity() {
|
||||
Point pnt = (Point) JTS.to( Wkt.fromWkt( "POINT Z( 3.41127795 8.11062269 2.611)", Wkt.Dialect.SFA_1_2_1 ) );
|
||||
EntityManager entityManager = createEntityManager();
|
||||
TestEntity test1 = new TestEntity( "radar 5", pnt );
|
||||
|
||||
entityManager.getTransaction().begin();
|
||||
entityManager.persist( test1 );
|
||||
entityManager.getTransaction().commit();
|
||||
|
||||
entityManager.close();
|
||||
}
|
||||
|
||||
// Entities are auto-discovered, so just add them anywhere on class-path
|
||||
// Add your tests, using standard JUnit.
|
||||
@Test
|
||||
public void hhh14523() throws Exception {
|
||||
|
||||
createtestEntity();
|
||||
|
||||
EntityManager entityManager = createEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
Query query = entityManager.createQuery( "select t from TestEntity t" );
|
||||
TestEntity ent = (TestEntity) query.getResultList().get( 0 );
|
||||
Point newPnt = (Point) JTS.to( Wkt.fromWkt( "POINT Z( 3.41127795 8.11062269 8.611)", Wkt.Dialect.SFA_1_2_1 ) );
|
||||
ent.setGeom( newPnt );
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();
|
||||
|
||||
|
||||
entityManager = createEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
List<TestEntity> entities = entityManager.createQuery( "select t from TestEntity t" ).getResultList();
|
||||
TestEntity ent2 = entities.get( 0 );
|
||||
try {
|
||||
assertEquals( 8.611, ent2.getGeom().getCoordinate().getZ(), 0.00001 );
|
||||
}
|
||||
finally {
|
||||
entityManager.getTransaction().commit();
|
||||
}
|
||||
entityManager.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "test")
|
||||
@SequenceGenerator(name = "test_id_seq", sequenceName = "test_id_seq", allocationSize = 1)
|
||||
class TestEntity implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "test_id_seq")
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
@Column(name = "uid", unique = true)
|
||||
private String uid;
|
||||
|
||||
@Column(name = "geom")
|
||||
private Point geom;
|
||||
|
||||
public TestEntity() {
|
||||
}
|
||||
|
||||
public TestEntity(String uid, Point geom) {
|
||||
this.uid = uid;
|
||||
this.geom = geom;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public void setUid(String uid) {
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public Point getGeom() {
|
||||
return geom;
|
||||
}
|
||||
|
||||
public void setGeom(Point geom) {
|
||||
this.geom = geom;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
//test case for bug HHH-14523
|
||||
package org.hibernate.spatial.integration.jts.hhh14523;
|
Loading…
Reference in New Issue