如何用Jackson读取指定URL的JSON数据并过滤为目标格式?
解决Jackson解析公交JSON数据为空的问题
需求说明
需要从http://data.foli.fi/siri/vm读取JSON数据,并转换为如下格式的数组:
[{ "latitude": 60.4827, "name": "14", "description": "14: Saramäki -> Erikvalla", "id": "550018", "longitude": 22.31275 }, { "latitude": 60.45902, "name": "20", "description": "20: Puutori -> Muhkuri", "id": "110416", "longitude": 22.26783 }]
当前问题
编写的ItemsBean解析后所有字段为空(或默认值),日志输出:
2022-08-17 11:43:34,714 INFO [get-map-data] (vert.x-worker-thread-1) null 2022-08-17 11:43:34,715 INFO [get-map-data] (vert.x-worker-thread-1) Data for the map: http://data.foli.fi/siri/vm 2022-08-17 11:43:34,716 INFO [get-map-data] (vert.x-worker-thread-1) [{ latitude: 0.0, name: null, description: null: null -> null, id: null, longitude: 0.0 }]
原ItemsBean代码:
public class ItemsBean{ private double latitude; @JsonProperty("name") private String publishedlinename; @JsonProperty("id") private String originname; private String destinationname; private String vehicleref; private double longitude; @JsonIgnore public String sys; public int servertime; public int responsetimestamp; public String producerref; public String responsemessageidentifier; public boolean status; public boolean moredata; public int recordedattime; public int validuntiltime; public int linkdistance; public double percentage; public String lineref; public String directionref; public String operatorref; public String originref; public String destinationref; public int originaimeddeparturetime; public int destinationaimedarrivaltime; public boolean monitored; public boolean incongestion; public boolean inpanic; public String delay; public int delaysecs; public String blockref; public String next_stoppointref; public int next_visitnumber; public String next_stoppointname; public boolean vehicleatstop; public String next_destinationdisplay; public int next_aimedarrivaltime; public int next_expectedarrivaltime; public int next_aimeddeparturetime; public String destinationname_sv; public String next_stoppointname_sv; public String __tripref; public String __routeref; public String __directionid; public String originname_sv; public String next_destinationdisplay_sv; public ItemsBean(){} public ItemsBean(double latitude, String publishedlinename, String originname, String destinationname, String vehicleref, double longitude) { this.latitude = latitude; this.publishedlinename = publishedlinename; this.originname = originname; this.destinationname = destinationname; this.vehicleref = vehicleref; this.longitude = longitude; } public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public String getPublishedlinename() { return publishedlinename; } public void setPublishedlinename(String publishedlinename) { this.publishedlinename = publishedlinename; } public String getOriginname() { return originname; } public void setOriginname(String originname) { this.originname = originname; } public String getNext_destinationdisplay() { return destinationname; } public void setDestinationname(String destinationname) { this.destinationname = destinationname; } public String getVehicleref() { return vehicleref; } public void setVehicleref(String vehicleref) { this.vehicleref = vehicleref; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } @Override public String toString() { return "\"" + "[{ " + "latitude: " + latitude + ", " + "name: " + publishedlinename + ", " + "description: " + publishedlinename + ": " + originname + " -> " + destinationname + ", " + "id: " + vehicleref + ", " + "longitude: " + longitude + " }]" + "\""; } }
问题分析
- JSON结构匹配错误:目标URL返回的JSON是多层嵌套结构,车辆数据实际位于
Siri.ServiceDelivery.VehicleMonitoringDelivery[0].VehicleActivity路径下,直接解析成ItemsBean数组无法定位到目标字段。 - JsonProperty注解逻辑颠倒:原代码将Java属性映射为输出字段名,而解析时需要将JSON中的原始字段名映射到Java属性,方向完全错误。
- 字段映射完全错误:比如目标
id对应JSON中的VehicleRef,name对应PublishedLineName,原代码的属性与JSON字段完全不匹配。 - 冗余字段未忽略:大量不需要的公共字段未添加
@JsonIgnore,干扰Jackson的字段匹配逻辑。
解决方案
步骤1:修正实体类结构
创建匹配原始JSON嵌套结构的类,仅保留需要的字段,多余字段全部忽略:
顶级响应类:SiriResponse.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; @JsonIgnoreProperties(ignoreUnknown = true) public class SiriResponse { @JsonProperty("Siri") private Siri siri; public Siri getSiri() { return siri; } public void setSiri(Siri siri) { this.siri = siri; } @JsonIgnoreProperties(ignoreUnknown = true) public static class Siri { @JsonProperty("ServiceDelivery") private ServiceDelivery serviceDelivery; public ServiceDelivery getServiceDelivery() { return serviceDelivery; } public void setServiceDelivery(ServiceDelivery serviceDelivery) { this.serviceDelivery = serviceDelivery; } } @JsonIgnoreProperties(ignoreUnknown = true) public static class ServiceDelivery { @JsonProperty("VehicleMonitoringDelivery") private List<VehicleMonitoringDelivery> vehicleMonitoringDeliveries; public List<VehicleMonitoringDelivery> getVehicleMonitoringDeliveries() { return vehicleMonitoringDeliveries; } public void setVehicleMonitoringDeliveries(List<VehicleMonitoringDelivery> vehicleMonitoringDeliveries) { this.vehicleMonitoringDeliveries = vehicleMonitoringDeliveries; } } @JsonIgnoreProperties(ignoreUnknown = true) public static class VehicleMonitoringDelivery { @JsonProperty("VehicleActivity") private List<VehicleActivity> vehicleActivities; public List<VehicleActivity> getVehicleActivities() { return vehicleActivities; } public void setVehicleActivities(List<VehicleActivity> vehicleActivities) { this.vehicleActivities = vehicleActivities; } } @JsonIgnoreProperties(ignoreUnknown = true) public static class VehicleActivity { @JsonProperty("MonitoredVehicleJourney") private MonitoredVehicleJourney monitoredVehicleJourney; @JsonProperty("VehicleLocation") private VehicleLocation vehicleLocation; public MonitoredVehicleJourney getMonitoredVehicleJourney() { return monitoredVehicleJourney; } public void setMonitoredVehicleJourney(MonitoredVehicleJourney monitoredVehicleJourney) { this.monitoredVehicleJourney = monitoredVehicleJourney; } public VehicleLocation getVehicleLocation() { return vehicleLocation; } public void setVehicleLocation(VehicleLocation vehicleLocation) { this.vehicleLocation = vehicleLocation; } } @JsonIgnoreProperties(ignoreUnknown = true) public static class MonitoredVehicleJourney { @JsonProperty("VehicleRef") private String vehicleRef; @JsonProperty("PublishedLineName") private String publishedLineName; @JsonProperty("OriginName") private String originName; @JsonProperty("DestinationName") private String destinationName; public String getVehicleRef() { return vehicleRef; } public void setVehicleRef(String vehicleRef) { this.vehicleRef = vehicleRef; } public String getPublishedLineName() { return publishedLineName; } public void setPublishedLineName(String publishedLineName) { this.publishedLineName = publishedLineName; } public String getOriginName() { return originName; } public void setOriginName(String originName) { this.originName = originName; } public String getDestinationName() { return destinationName; } public void setDestinationName(String destinationName) { this.destinationName = destinationName; } } @JsonIgnoreProperties(ignoreUnknown = true) public static class VehicleLocation { @JsonProperty("Latitude") private double latitude; @JsonProperty("Longitude") private double longitude; public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } } }
目标输出类:MapVehicle.java
public class MapVehicle { private double latitude; private String name; private String description; private String id; private double longitude; public MapVehicle(double latitude, String name, String description, String id, double longitude) { this.latitude = latitude; this.name = name; this.description = description; this.id = id; this.longitude = longitude; } // Getters and Setters public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getId() { return id; } public void setId(String id) { this.id = id; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } }
步骤2:解析并转换数据
编写代码读取URL数据,解析后转换成目标格式:
import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.net.URL; import java.util.List; import java.util.stream.Collectors; public class VehicleDataParser { private static final ObjectMapper objectMapper = new ObjectMapper(); public static void main(String[] args) throws IOException { // 读取并解析原始JSON URL url = new URL("http://data.foli.fi/siri/vm"); SiriResponse response = objectMapper.readValue(url, SiriResponse.class); // 提取车辆数据并转换成目标格式 List<MapVehicle> mapVehicles = response.getSiri().getServiceDelivery().getVehicleMonitoringDeliveries().get(0) .getVehicleActivities().stream() .map(activity -> { SiriResponse.MonitoredVehicleJourney journey = activity.getMonitoredVehicleJourney(); SiriResponse.VehicleLocation location = activity.getVehicleLocation(); String description = String.format("%s: %s -> %s", journey.getPublishedLineName(), journey.getOriginName(), journey.getDestinationName()); return new MapVehicle( location.getLatitude(), journey.getPublishedLineName(), description, journey.getVehicleRef(), location.getLongitude() ); }) .collect(Collectors.toList()); // 输出目标格式的JSON System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapVehicles)); } }
关键修正点
- 嵌套结构匹配:通过多层静态类精准匹配原始JSON的嵌套路径,确保Jackson能正确定位到车辆数据。
- 字段映射准确:
@JsonProperty注解完全对应原始JSON中的字段名,保证解析时字段能正确赋值。 - 忽略未知字段:所有类添加
@JsonIgnoreProperties(ignoreUnknown = true),避免多余字段干扰解析逻辑。 - 分离解析与转换:先解析原始数据,再通过Stream API转换成目标格式,逻辑清晰易维护。
验证结果
运行代码后,将输出符合需求的JSON数组,每个对象的latitude、name、description、id、longitude字段均会被正确填充。
内容的提问来源于stack exchange,提问作者MikaelL
相关产品推荐
相关产品推荐

