在上一篇博文《geometry:MySQL的空间数据类型(Spatial Data Type)与JTS(OSGeo)类型之间的序列化和反序列化》中,实现了对MySQL数据库存储的WKB数据到JTS Geometry对象之间的转换。
当我们从数据库中得到的Geometry对象后,我们需要把它提供给前端时,就需要将它转为JSON格式,或从前端将JSON数据反序列化为Geometry对象。本文说明使用JSON工具库Jackson如何实现这个过程。
JTS Geometry对象不是标准的Java Bean不能自动被Jackson执行序列化和反序列化。所以我们需要为 Geometry对象实现自定义的序列化器和反序列化器。
我的实现方式就是将Geometry对象序列化为字符串,即WKT(Well-Known Text)字符串。
JTS库依赖引入
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
序列化器实现
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.vividsolutions.jts.geom.Geometry;
/**
* Serializing Geometry property as WKT String with Jackson<br>
* @author guyadong
* @param <T>
*/
public class GeometrySerializer<T extends Geometry> extends JsonSerializer<T> {
@Override
public void serialize(T value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeString(value.toText());
}
}
反序列化器实现
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.google.common.base.Strings;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
/**
* Deserialize WKT property as Geometry Object with Jackson<br>
* @author guyadong
* @param <T>
*/
public class GeometryDeserializer<T extends Geometry> extends JsonDeserializer<T> {
@SuppressWarnings("unchecked")
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
try {
String text = jp.getValueAsString();
if(Strings.isNullOrEmpty(text)) {
return null;
}
WKTReader reader = new WKTReader();
return (T) reader.read(text);
} catch (ParseException e) {
throw new IOException(e);
}
}
}
注解方式引用
如下可以在以使用JsonDeserialize和JsonSerialize注解定义类成员字段的自定义序列化和反序列化器:
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = gu.sql2java.geometry.jackson.GeometryDeserializer.class)
@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = gu.sql2java.geometry.jackson.GeometrySerializer.class)
private com.vividsolutions.jts.geom.Point spot;
调用示例
import static org.junit.Assert.*;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.vividsolutions.jts.geom.Point;
public class GeometryJacksonTest {
@Test
public void test1Codec() {
try {
/** JSON 格式字符串,保存WKT格式的坐标数据 */
String jsonWKT = "\"POINT (1.75 -1.222)\"";
System.out.printf("jsonWKT \t%s\n",jsonWKT);
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
/** 指定 Point类的序列化器 */
simpleModule.addSerializer(Point.class, new GeometrySerializer<Point>());
/** 指定 Point类的反序列化器 */
simpleModule.addDeserializer(Point.class, new GeometryDeserializer<Point>());
objectMapper.registerModule(simpleModule);
/** 反序列化为Point对象 */
Point deserialized = objectMapper.readValue(jsonWKT,Point.class);
System.out.printf("deserialized\t%s\n",deserialized.toText());
/** 序列化为JSON 字符串 */
String serialized = objectMapper.writeValueAsString(deserialized);
System.out.printf("serialized \t%s\n",serialized);
assertTrue(jsonWKT.equals(serialized));
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
}
}
}
输出
jsonWKT “POINT (1.75 -1.222)”
deserialized POINT (1.75 -1.222)
serialized “POINT (1.75 -1.222)”
完整代码参见我的码云仓库:https://gitee.com/l0km/sql2java/tree/dev/sql2java-base/src/main/java/gu/sql2java/geometry/jackson
https://gitee.com/l0km/sql2java/blob/dev/sql2java-base/src/test/java/gu/sql2java/GeometryJacksonTest.java