package com.cdzy.operations.handler; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.postgresql.geometric.PGpoint; import org.postgresql.geometric.PGpolygon; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * PGpolygon 反序列化器 - 将 JSON 反序列化为 PGpolygon */ @Slf4j public class PGpolygonDeserializer extends JsonDeserializer { @Override public PGpolygon deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); if (node.isNull()) { return null; } try { PGpolygon result = null; // 格式1: 自定义格式 {"type": "polygon", "coordinates": [[x1,y1], [x2,y2], ...]} if (node.isObject() && node.has("type")) { String type = node.get("type").asText(); if ("polygon".equals(type)) { result = parseFromCustomFormat(node); } else if ("Polygon".equals(type)) { result = parseFromGeoJSON(node); } } // 格式2: 直接坐标数组 [[x1,y1], [x2,y2], ...] else if (node.isArray()) { result = parseFromArray(node); } // 格式3: 字符串格式 "((x1 y1, x2 y2, ...))" else if (node.isTextual()) { result = parseFromString(node.asText()); } // 格式4: 对象格式但没有 type 字段,尝试解析 coordinates else if (node.isObject() && node.has("coordinates")) { result = parseFromCustomFormat(node); } if (result == null) { throw new IOException(""" 不支持的 PGpolygon JSON 格式,支持的格式包括: 1. 自定义格式: {"type":"polygon","coordinates":[[x1,y1],[x2,y2],...]} 2. GeoJSON格式: {"type":"Polygon","coordinates":[[[x1,y1],[x2,y2],...]]} 3. 坐标数组: [[x1,y1],[x2,y2],...] 4. 字符串格式: "((x1 y1, x2 y2, ...))\""""); } return result; } catch (Exception e) { System.err.println("!!! PGpolygonDeserializer 反序列化失败 !!!"); System.err.println("错误信息: " + e.getMessage()); System.err.println("输入 JSON: " + node); throw new IOException("PGpolygon 反序列化失败: " + e.getMessage(), e); } } @Override public Class handledType() { return PGpolygon.class; } /** * 解析自定义格式 */ private PGpolygon parseFromCustomFormat(JsonNode node) throws IOException { JsonNode coordinatesNode = node.get("coordinates"); if (coordinatesNode == null) { throw new IOException("coordinates 字段缺失"); } if (!coordinatesNode.isArray()) { throw new IOException("coordinates 字段必须是数组类型"); } List points = new ArrayList<>(); for (int i = 0; i < coordinatesNode.size(); i++) { JsonNode coordNode = coordinatesNode.get(i); if (!coordNode.isArray()) { throw new IOException("坐标 " + i + " 必须是数组格式"); } if (coordNode.size() < 2) { throw new IOException("坐标 " + i + " 至少需要2个值(经度和纬度)"); } try { double x = coordNode.get(0).asDouble(); double y = coordNode.get(1).asDouble(); PGpoint point = new PGpoint(x, y); points.add(point); } catch (NumberFormatException e) { throw new IOException("坐标 " + i + " 格式错误: " + coordNode, e); } } return createPGpolygonFromPoints(points); } /** * 解析 GeoJSON 格式 */ private PGpolygon parseFromGeoJSON(JsonNode node) throws IOException { JsonNode coordinatesNode = node.get("coordinates"); if (coordinatesNode == null) { throw new IOException("coordinates 字段缺失"); } if (!coordinatesNode.isArray() || coordinatesNode.isEmpty()) { throw new IOException("coordinates 字段必须是非空数组"); } // GeoJSON 格式: coordinates 是三维数组 [[[x1,y1], [x2,y2], ...]] List points = new ArrayList<>(); for (int i = 0; i < coordinatesNode.size(); i++) { JsonNode ringNode = coordinatesNode.get(i); if (!ringNode.isArray()) { throw new IOException("GeoJSON coordinates 第一环必须是数组"); } if (!ringNode.isArray()) { throw new IOException("GeoJSON 坐标 " + i + " 必须是数组格式"); } if (ringNode.size() < 2) { throw new IOException("GeoJSON 坐标 " + i + " 至少需要2个值(经度和纬度)"); } try { double x = ringNode.get(0).asDouble(); double y = ringNode.get(1).asDouble(); PGpoint point = new PGpoint(x, y); points.add(point); } catch (NumberFormatException e) { throw new IOException("GeoJSON 坐标 " + i + " 格式错误: " + ringNode, e); } } return createPGpolygonFromPoints(points); } /** * 解析坐标数组格式 */ private PGpolygon parseFromArray(JsonNode node) throws IOException { List points = new ArrayList<>(); for (int i = 0; i < node.size(); i++) { JsonNode coordNode = node.get(i); if (!coordNode.isArray()) { throw new IOException("坐标 " + i + " 必须是数组格式"); } if (coordNode.size() < 2) { throw new IOException("坐标 " + i + " 至少需要2个值(经度和纬度)"); } try { double x = coordNode.get(0).asDouble(); double y = coordNode.get(1).asDouble(); PGpoint point = new PGpoint(x, y); points.add(point); } catch (NumberFormatException e) { throw new IOException("坐标 " + i + " 格式错误: " + coordNode, e); } } return createPGpolygonFromPoints(points); } /** * 解析字符串格式 */ private PGpolygon parseFromString(String polygonString) throws IOException { if (polygonString == null || polygonString.trim().isEmpty()) { throw new IOException("多边形字符串为空"); } try { PGpolygon polygon = new PGpolygon(polygonString); System.out.println("字符串解析成功"); return polygon; } catch (Exception e) { throw new IOException("PGpolygon 字符串格式解析失败: " + polygonString, e); } } /** * 从点列表创建 PGpolygon */ private PGpolygon createPGpolygonFromPoints(List points) throws IOException { if (points == null) { throw new IOException("点列表为 null"); } if (points.size() < 3) { throw new IOException("多边形至少需要3个点,当前只有 " + points.size() + " 个点"); } // 检查点是否为 null for (int i = 0; i < points.size(); i++) { if (points.get(i) == null) { throw new IOException("第 " + i + " 个点为 null"); } } try { // 构建正确的多边形字符串格式 StringBuilder sb = new StringBuilder(); for (int i = 0; i < points.size(); i++) { PGpoint point = points.get(i); if (i == 0) { sb.append("("); // 开始内括号 } sb.append("(").append(point.x).append(",").append(point.y).append(")"); if (i < points.size() - 1) { sb.append(","); } else { sb.append(")"); // 结束内括号 } } // 确保多边形闭合 PGpoint firstPoint = points.get(0); PGpoint lastPoint = points.get(points.size() - 1); if (firstPoint.x != lastPoint.x || firstPoint.y != lastPoint.y) { log.info("多边形未闭合,添加首点以闭合"); sb.append(",(").append(firstPoint.x).append(",").append(firstPoint.y).append(")"); } String polygonString = sb.toString(); return new PGpolygon(polygonString); } catch (Exception e) { throw new IOException("创建 PGpolygon 失败: " + e.getMessage(), e); } } }