Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

SOLVED: Eclipselink: Custom StructConverter for Spatial never called

mexxpower99:

I've ran into a problem concerning complex objects and Eclipselink which I can't seem to solve. I need to write / read spatial data as SDO_GEOMETRY to my Oracle database.

I used to use oracle.spatial.geometry.JGeometry, but for querying reasons I need to switch to org.geolatte.geom.Geometry (which is the spatial type used by QueryDSL). So I wrote a custom implementation of org.eclipse.persistence.platform.database.converters.StructConverter to handle the conversion from org.geolatte.geom.Geometry to SDO_GEOMETRY / Struct.

I used org.eclipse.persistence.platform.database.oracle.converters.JGeometryConverter as a template.


import com.mysema.query.sql.spatial.JGeometryConverter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Struct;
import oracle.spatial.geometry.JGeometry;
import org.eclipse.persistence.platform.database.converters.StructConverter;
import org.geolatte.geom.Geometry;

public class GeometryConverter implements StructConverter {
private static final String JGEOMETRY_DB_TYPE = "MDSYS.SDO_GEOMETRY";
private Class JGEOMETRY_CLASS;
private MethodHandle loadJSMethod;
private MethodHandle storeJSMethod;

public GeometryConverter() {
try {
JGEOMETRY_CLASS = Class.forName("oracle.spatial.geometry.JGeometry");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}

MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
loadJSMethod = lookup.unreflect(JGEOMETRY_CLASS.getMethod("loadJS", new Class[] {
Struct.class
}));
storeJSMethod = lookup.unreflect(JGEOMETRY_CLASS.getMethod("storeJS", new Class[] {
JGEOMETRY_CLASS,
Connection.class
}));
} catch (IllegalAccessException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}

@Override
public String getStructName() {
return JGEOMETRY_DB_TYPE;
}

@Override
public Class getJavaType() {
return Geometry.class;
}

@Override
public Object convertToObject(Struct struct) throws SQLException {
System.out.println("-------------------- CALLED convertToObject");
if (struct == null) {
return null;
}
try {
return JGeometryConverter.convert((JGeometry)loadJSMethod.invokeWithArguments(new Object[] {
struct
}));

} catch (Throwable throwable) {
throw new SQLException(throwable);
}
}

@Override
public Struct convertToStruct(Object geometry, Connection connection) throws SQLException {
System.out.println("-------------------- CALLED convertToStruct");
if (geometry == null) {
return null;
}
try {
return (Struct) storeJSMethod.invokeWithArguments(new Object[] {
JGeometryConverter.convert((Geometry)geometry), connection
});
} catch (Throwable throwable) {
throw new SQLException(throwable);
}
}
}

My entity Class is annotated the following way:


//Real package replaced by 'myPkg' for privacy reasons
@StructConverter(name = "Geometry", converter = "myPkg.GeometryConverter")
@Table(name = "ENTRY", catalog = "")
public class Entry implements Serializable {
...

@Column(name = "LOCATION")
@Convert("Geometry")
private Geometry location;
...
}

But for some odd reason the method convertToStruct of my converter is not called when calling entityManager.persist(myEntryObject). Instead I get the following exception:


Caused by: java.sql.SQLException: Invalid column type
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8488)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:7995)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8735)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8714)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:219)
at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.setParameterValueInDatabaseCall(DatabasePlatform.java:2506)
at org.eclipse.persistence.platform.database.oracle.Oracle9Platform.setParameterValueInDatabaseCall(Oracle9Platform.java:525)
at org.eclipse.persistence.internal.databaseaccess.BindCallCustomParameter.set(BindCallCustomParameter.java:69)
at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.setParameterValueInDatabaseCall(DatabasePlatform.java:2500)
at org.eclipse.persistence.platform.database.oracle.Oracle9Platform.setParameterValueInDatabaseCall(Oracle9Platform.java:525)
at org.eclipse.persistence.internal.databaseaccess.DatabaseCall.prepareStatement(DatabaseCall.java:797)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:621)
... 101 more

What is so odd about this is that when retrieving Entry objects via the EntityManager convertToObject is indeed called and it works perfectly. But every time I try to insert / update an Entry it doesn't work.

Is there any additional configuration I have to do to make EclipseLink recognize my converter? What else could be the cause of this problem?

I hope someone can help me. Thank you in advance.

EDIT My persistence unit looks like this:





org.eclipse.persistence.jpa.PersistenceProvider
java:app/aphrodite4
false









I am loading it the following way:


@PersistenceContext(unitName = "jtaUnit")
protected EntityManager em;



Posted in S.E.F
via StackOverflow & StackExchange Atomic Web Robots
This Question have been answered
HERE


This post first appeared on Stack Solved, please read the originial post: here

Share the post

SOLVED: Eclipselink: Custom StructConverter for Spatial never called

×

Subscribe to Stack Solved

Get updates delivered right to your inbox!

Thank you for your subscription

×