You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Stream/Jackson将Google Places API地址组件填充到Java实体类

问题描述

我拿到了Google Places API返回的address_components数据如下:

"address_components": [
      {
        "long_name": "123",
        "short_name": "123",
        "types": ["street_number"]
      },
      {
        "long_name": "Mulgoa Road",
        "short_name": "Mulgoa Rd",
        "types": ["route"]
      },
      {
        "long_name": "Penrith",
        "short_name": "Penrith",
        "types": ["locality", "political"]
      },
      {
        "long_name": "City of Penrith",
        "short_name": "City of Penrith",
        "types": ["administrative_area_level_2", "political"]
      },
      {
        "long_name": "New South Wales",
        "short_name": "NSW",
        "types": ["administrative_area_level_1", "political"]
      },
      {
        "long_name": "Australia",
        "short_name": "AU",
        "types": ["country", "political"]
      },
      {
        "long_name": "2750",
        "short_name": "2750",
        "types": ["postal_code"]
      }
    ]

期望转换成如下格式的响应:

{
        "postcode": "2750",
        "unit_number": null,
        "floor_number": null,
        "building_name": null,
        "building_number": null,
        "block_number": null,
        "street_number": "123",
        "street_name": "Mulgoa",
        "street_type": "Road",
        "state": "New South Wales",
        "suburb": "Penrith",
        "city": "City of Penrith",
        "district": null,
        "fullAddress": "123 Mulgoa Road, Penrith NSW 2750, Australia"
    }

当前已有部分实现代码:

JsonNode resultData = new ObjectMapper().readTree(String.valueOf(response.getResponseBody()));
if (Objects.equals(resultData.get("status").asText(), "OK")) {
    JsonNode addressComponentsArray = resultData.get("result").get("address_components");
    LocationAddressComponent responseObject = new LocationAddressComponent();

    if (addressComponentsArray.isArray()) {
        for (JsonNode jsonNode : addressComponentsArray) {
            Array res = jsonNode.get("types");
            // 待填充逻辑
        }
    }
}

实体类LocationAddressComponent.java定义:

public class LocationAddressComponent {
    String postcode;
    String unit_number;
    String floor_number;
    String building_name;
    String building_number;
    String block_number;
    String street_number;
    String street_name;
    String street_type;
    String state;
    String suburb;
    String city;
    String district;
    String fullAddress;

    // 需添加getter、setter,或用Lombok注解简化
}

需要给出基于Stream或Jackson完成数据填充的具体方案。


方案一:Stream遍历映射 + 手动赋值

利用Java Stream遍历地址组件数组,通过类型匹配完成字段赋值,最后拼接完整地址。

JsonNode resultData = new ObjectMapper().readTree(String.valueOf(response.getResponseBody()));
if (Objects.equals(resultData.get("status").asText(), "OK")) {
    JsonNode addressComponentsArray = resultData.get("result").get("address_components");
    LocationAddressComponent responseObject = new LocationAddressComponent();

    if (addressComponentsArray.isArray()) {
        // 将JsonNode数组转为Stream处理
        StreamSupport.stream(addressComponentsArray.spliterator(), false)
                .forEach(component -> {
                    List<String> types = component.get("types")
                            .findValuesAsText()
                            .stream()
                            .collect(Collectors.toList());
                    String longName = component.get("long_name").asText();
                    String shortName = component.get("short_name").asText();

                    // 按类型匹配赋值
                    if (types.contains("street_number")) {
                        responseObject.setStreet_number(longName);
                    } else if (types.contains("route")) {
                        // 拆分街道名与类型(如Mulgoa Road拆为Mulgoa和Road)
                        String[] streetParts = longName.split(" ", 2);
                        if (streetParts.length == 2) {
                            responseObject.setStreet_name(streetParts[0]);
                            responseObject.setStreet_type(streetParts[1]);
                        } else {
                            responseObject.setStreet_name(longName);
                        }
                    } else if (types.contains("locality")) {
                        responseObject.setSuburb(longName);
                    } else if (types.contains("administrative_area_level_2")) {
                        responseObject.setCity(longName);
                    } else if (types.contains("administrative_area_level_1")) {
                        responseObject.setState(longName);
                    } else if (types.contains("postal_code")) {
                        responseObject.setPostcode(longName);
                    }
                });

        // 拼接完整地址
        StringBuilder fullAddr = new StringBuilder();
        Optional.ofNullable(responseObject.getStreet_number()).ifPresent(s -> fullAddr.append(s).append(" "));
        if (responseObject.getStreet_name() != null && responseObject.getStreet_type() != null) {
            fullAddr.append(responseObject.getStreet_name()).append(" ").append(responseObject.getStreet_type());
        } else {
            Optional.ofNullable(responseObject.getStreet_name()).ifPresent(fullAddr::append);
        }
        Optional.ofNullable(responseObject.getSuburb()).ifPresent(s -> fullAddr.append(", ").append(s));
        
        // 补充州缩写和邮编
        JsonNode stateComponent = StreamSupport.stream(addressComponentsArray.spliterator(), false)
                .filter(n -> n.get("types").findValuesAsText().contains("administrative_area_level_1"))
                .findFirst().orElse(null);
        if (stateComponent != null && responseObject.getPostcode() != null) {
            fullAddr.append(" ").append(stateComponent.get("short_name").asText()).append(" ").append(responseObject.getPostcode());
        }
        fullAddr.append(", Australia");
        responseObject.setFullAddress(fullAddr.toString().trim());
    }
}

注意:

  • 需给LocationAddressComponent添加所有字段的getter/setter,或使用Lombok的@Data注解自动生成。
  • 街道名拆分逻辑需根据实际地区格式调整,部分场景可能需要更灵活的处理。

方案二:Jackson自定义反序列化器

通过自定义Jackson反序列化器,直接将API响应映射到目标实体类,代码更符合序列化规范且复用性强。

步骤1:编写自定义反序列化器

public class LocationAddressDeserializer extends StdDeserializer<LocationAddressComponent> {

    public LocationAddressDeserializer() {
        this(null);
    }

    public LocationAddressDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public LocationAddressComponent deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode root = p.getCodec().readTree(p);
        JsonNode addressComponents = root.get("result").get("address_components");
        LocationAddressComponent addr = new LocationAddressComponent();
        String stateShort = null;

        // 遍历赋值
        for (JsonNode component : addressComponents) {
            List<String> types = component.get("types").findValuesAsText();
            String longName = component.get("long_name").asText();
            String shortName = component.get("short_name").asText();

            if (types.contains("street_number")) {
                addr.setStreet_number(longName);
            } else if (types.contains("route")) {
                String[] streetParts = longName.split(" ", 2);
                if (streetParts.length == 2) {
                    addr.setStreet_name(streetParts[0]);
                    addr.setStreet_type(streetParts[1]);
                } else {
                    addr.setStreet_name(longName);
                }
            } else if (types.contains("locality")) {
                addr.setSuburb(longName);
            } else if (types.contains("administrative_area_level_2")) {
                addr.setCity(longName);
            } else if (types.contains("administrative_area_level_1")) {
                addr.setState(longName);
                stateShort = shortName;
            } else if (types.contains("postal_code")) {
                addr.setPostcode(longName);
            }
        }

        // 拼接完整地址
        StringBuilder fullAddr = new StringBuilder();
        Optional.ofNullable(addr.getStreet_number()).ifPresent(s -> fullAddr.append(s).append(" "));
        if (addr.getStreet_name() != null && addr.getStreet_type() != null) {
            fullAddr.append(addr.getStreet_name()).append(" ").append(addr.getStreet_type());
        } else {
            Optional.ofNullable(addr.getStreet_name()).ifPresent(fullAddr::append);
        }
        Optional.ofNullable(addr.getSuburb()).ifPresent(s -> fullAddr.append(", ").append(s));
        if (stateShort != null && addr.getPostcode() != null) {
            fullAddr.append(" ").append(stateShort).append(" ").append(addr.getPostcode());
        }
        fullAddr.append(", Australia");
        addr.setFullAddress(fullAddr.toString().trim());

        return addr;
    }
}

步骤2:给实体类添加反序列化注解

@Data // Lombok注解,自动生成getter、setter等方法
@JsonDeserialize(using = LocationAddressDeserializer.class)
public class LocationAddressComponent {
    String postcode;
    String unit_number;
    String floor_number;
    String building_name;
    String building_number;
    String block_number;
    String street_number;
    String street_name;
    String street_type;
    String state;
    String suburb;
    String city;
    String district;
    String fullAddress;
}

步骤3:直接反序列化API响应

ObjectMapper mapper = new ObjectMapper();
// 注册Lombok模块,确保Jackson能识别Lombok生成的方法(需引入jackson-datatype-lombok依赖)
mapper.registerModule(new LombokModule());

try {
    LocationAddressComponent responseObject = mapper.readValue(response.getResponseBody(), LocationAddressComponent.class);
    // 使用responseObject
} catch (IOException e) {
    e.printStackTrace();
}

内容的提问来源于stack exchange,提问作者xMayank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:11:07