Apache Cayenne > Index > Cayenne Examples > Mapping JTS Geometries

The JTS Topology Suite is a very nice library for handling geometries in Java. On a related subject, for doing spatial operations in the database, use something like PostGIS http://www.postgis.org/.

This is an ExtendedType that stores/reads a JTS Geometry as a WKT (Well-Known Text as defined by OpenGis Consortium).

WKTGeometryType.java
package cayenne.examples;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Types;

import org.apache.cayenne.access.types.AbstractType;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.validation.BeanValidationFailure;
import org.apache.cayenne.validation.ValidationResult;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.WKTReader;

/**
 * An ExtendedType that can be used by cayenne to covert WKT to/from JTS
 * Geometry - com.vividsolutions.jts.geom.Geometry
 * 
 * http://www.jump-project.org/project.php?PID=JTS&SID=OVER
 * http://www.objectstyle.org/cayenne/userguide/access-stack/extended-types.html
 */
public class WKTGeometryType extends AbstractType {

    private static final String CHARSET = "UTF-8";

    private Class geometryClass;

    public WKTGeometryType(Class geometryClass) {
        this.geometryClass = geometryClass;
    }

    public String getClassName() {
        return geometryClass.getName();
    }

    public boolean validateProperty(Object source, String property, Object value,
            DbAttribute dbAttribute, ValidationResult validationResult) {
        Geometry g = (Geometry) value;
        if (!g.isValid()) {
            String msg = "Invalid geometry";
            validationResult.addFailure(new BeanValidationFailure(source, property, msg));
            return false;
        }
        return true;
    }

    public void setJdbcObject(PreparedStatement statement, Object value, int pos, int type,
            int precision) throws Exception {
        Geometry g = (Geometry) value;
        switch (type) {
        case Types.BLOB:
            statement.setBytes(pos, g.toText().getBytes(CHARSET));
            break;
        default:
            statement.setString(pos, g.toText());
            break;
        }
    }

    public Object materializeObject(ResultSet rs, int index, int type) throws Exception {
        String wkt = null;
        switch (type) {
        case Types.BLOB:
            wkt = new String(rs.getBytes(index), CHARSET);
            break;
        default:
            wkt = rs.getString(index);
            break;
        }
        if (wkt == null) {
            return (Geometry) null;
        }
        // create WKTReader using application ThreadLocal GeometryFactory
        return new WKTReader(GeometryHelper.geometryFactory()).read(wkt);
    }

    public Object materializeObject(CallableStatement rs, int index, int type) throws Exception {
        String wkt = null;
        switch (type) {
        case Types.BLOB:
            wkt = new String(rs.getBytes(index), CHARSET);
            break;
        default:
            wkt = rs.getString(index);
            break;
        }
        if (wkt == null) {
            return (Geometry) null;
        }
        // create WKTReader using application ThreadLocal GeometryFactory
        return new WKTReader(GeometryHelper.geometryFactory()).read(wkt);
    }
}

Register this extended type.

ExtendedTypeMap extendedTypes = node.getAdapter().getExtendedTypes();
extendedTypes.registerType(new WKTGeometryType(Geometry.class));