解析与Spring引导RestTemplate嵌套元素给JSON解析错误
我想消费REST接口,让下面的输出(准确地说,我想找回TAF元素的列表):解析与Spring引导RestTemplate嵌套元素给JSON解析错误
<?xml version="1.0" encoding="UTF-8"?>
<response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XML-Schema-instance" version="1.2" xsi:noNamespaceSchemaLocation="http://aviationweather.gov/adds/schema/taf1_2.xsd">
<request_index>32084191</request_index>
<data_source name="tafs" />
<request type="retrieve" />
<errors />
<warnings />
<time_taken_ms>13</time_taken_ms>
<data num_results="4">
<TAF>
<raw_text>TAF EPGD 171130Z 1712/1812 25008KT CAVOK PROB40 1718/1806 1500 BR BKN005</raw_text>
<station_id>EPGD</station_id>
<issue_time>2017-10-17T11:30:00Z</issue_time>
<bulletin_time>2017-10-17T11:00:00Z</bulletin_time>
<valid_time_from>2017-10-17T12:00:00Z</valid_time_from>
<valid_time_to>2017-10-18T12:00:00Z</valid_time_to>
<latitude>54.37</latitude>
<longitude>18.47</longitude>
<elevation_m>138.0</elevation_m>
<forecast>
<fcst_time_from>2017-10-17T12:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-18T12:00:00Z</fcst_time_to>
<wind_dir_degrees>250</wind_dir_degrees>
<wind_speed_kt>8</wind_speed_kt>
<visibility_statute_mi>6.21</visibility_statute_mi>
<wx_string>NSW</wx_string>
<sky_condition sky_cover="NSC" />
</forecast>
<forecast>
<fcst_time_from>2017-10-17T18:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-18T06:00:00Z</fcst_time_to>
<change_indicator>PROB</change_indicator>
<probability>40</probability>
<visibility_statute_mi>0.93</visibility_statute_mi>
<wx_string>BR</wx_string>
<sky_condition sky_cover="BKN" cloud_base_ft_agl="500" />
</forecast>
</TAF>
<TAF>
<raw_text>TAF EPGD 170530Z 1706/1806 22010KT 0300 FG BKN002 BECMG 1707/1709 CAVOK</raw_text>
<station_id>EPGD</station_id>
<issue_time>2017-10-17T05:30:00Z</issue_time>
<bulletin_time>2017-10-17T05:00:00Z</bulletin_time>
<valid_time_from>2017-10-17T06:00:00Z</valid_time_from>
<valid_time_to>2017-10-18T06:00:00Z</valid_time_to>
<latitude>54.37</latitude>
<longitude>18.47</longitude>
<elevation_m>138.0</elevation_m>
<forecast>
<fcst_time_from>2017-10-17T06:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T07:00:00Z</fcst_time_to>
<wind_dir_degrees>220</wind_dir_degrees>
<wind_speed_kt>10</wind_speed_kt>
<visibility_statute_mi>0.19</visibility_statute_mi>
<wx_string>FG</wx_string>
<sky_condition sky_cover="BKN" cloud_base_ft_agl="200" />
</forecast>
<forecast>
<fcst_time_from>2017-10-17T07:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-18T06:00:00Z</fcst_time_to>
<change_indicator>BECMG</change_indicator>
<time_becoming>2017-10-17T09:00:00Z</time_becoming>
<wind_dir_degrees>220</wind_dir_degrees>
<wind_speed_kt>10</wind_speed_kt>
<visibility_statute_mi>6.21</visibility_statute_mi>
<wx_string>NSW</wx_string>
<sky_condition sky_cover="NSC" />
</forecast>
</TAF>
<TAF>
<raw_text>TAF EPGD 162330Z 1700/1724 24006KT 7000 SCT012 TEMPO 1700/1708 BKN005 PROB40 1702/1707 1000 BR OVC002</raw_text>
<station_id>EPGD</station_id>
<issue_time>2017-10-16T23:30:00Z</issue_time>
<bulletin_time>2017-10-16T23:00:00Z</bulletin_time>
<valid_time_from>2017-10-17T00:00:00Z</valid_time_from>
<valid_time_to>2017-10-18T00:00:00Z</valid_time_to>
<latitude>54.37</latitude>
<longitude>18.47</longitude>
<elevation_m>138.0</elevation_m>
<forecast>
<fcst_time_from>2017-10-17T00:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T08:00:00Z</fcst_time_to>
<change_indicator>TEMPO</change_indicator>
<sky_condition sky_cover="BKN" cloud_base_ft_agl="500" />
</forecast>
<forecast>
<fcst_time_from>2017-10-17T00:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-18T00:00:00Z</fcst_time_to>
<wind_dir_degrees>240</wind_dir_degrees>
<wind_speed_kt>6</wind_speed_kt>
<visibility_statute_mi>4.35</visibility_statute_mi>
<sky_condition sky_cover="SCT" cloud_base_ft_agl="1200" />
</forecast>
<forecast>
<fcst_time_from>2017-10-17T02:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T07:00:00Z</fcst_time_to>
<change_indicator>PROB</change_indicator>
<probability>40</probability>
<visibility_statute_mi>0.62</visibility_statute_mi>
<wx_string>BR</wx_string>
<sky_condition sky_cover="OVC" cloud_base_ft_agl="200" />
</forecast>
</TAF>
<TAF>
<raw_text>TAF EPGD 161730Z 1618/1718 24006KT CAVOK BECMG 1618/1620 BKN013 TEMPO 1621/1708 BKN005 PROB40 1700/1707 2000 BR OVC002 BECMG 1709/1711 SCT030</raw_text>
<station_id>EPGD</station_id>
<issue_time>2017-10-16T17:30:00Z</issue_time>
<bulletin_time>2017-10-16T17:00:00Z</bulletin_time>
<valid_time_from>2017-10-16T18:00:00Z</valid_time_from>
<valid_time_to>2017-10-17T18:00:00Z</valid_time_to>
<latitude>54.37</latitude>
<longitude>18.47</longitude>
<elevation_m>138.0</elevation_m>
<forecast>
<fcst_time_from>2017-10-16T18:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T18:00:00Z</fcst_time_to>
<wind_dir_degrees>240</wind_dir_degrees>
<wind_speed_kt>6</wind_speed_kt>
<visibility_statute_mi>6.21</visibility_statute_mi>
<wx_string>NSW</wx_string>
<sky_condition sky_cover="NSC" />
</forecast>
<forecast>
<fcst_time_from>2017-10-16T18:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T09:00:00Z</fcst_time_to>
<change_indicator>BECMG</change_indicator>
<time_becoming>2017-10-16T20:00:00Z</time_becoming>
<wind_dir_degrees>240</wind_dir_degrees>
<wind_speed_kt>6</wind_speed_kt>
<visibility_statute_mi>6.21</visibility_statute_mi>
<wx_string>NSW</wx_string>
<sky_condition sky_cover="BKN" cloud_base_ft_agl="1300" />
</forecast>
<forecast>
<fcst_time_from>2017-10-16T21:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T08:00:00Z</fcst_time_to>
<change_indicator>TEMPO</change_indicator>
<sky_condition sky_cover="BKN" cloud_base_ft_agl="500" />
</forecast>
<forecast>
<fcst_time_from>2017-10-17T00:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T07:00:00Z</fcst_time_to>
<change_indicator>PROB</change_indicator>
<probability>40</probability>
<visibility_statute_mi>1.24</visibility_statute_mi>
<wx_string>BR</wx_string>
<sky_condition sky_cover="OVC" cloud_base_ft_agl="200" />
</forecast>
<forecast>
<fcst_time_from>2017-10-17T09:00:00Z</fcst_time_from>
<fcst_time_to>2017-10-17T18:00:00Z</fcst_time_to>
<change_indicator>BECMG</change_indicator>
<time_becoming>2017-10-17T11:00:00Z</time_becoming>
<wind_dir_degrees>240</wind_dir_degrees>
<wind_speed_kt>6</wind_speed_kt>
<visibility_statute_mi>6.21</visibility_statute_mi>
<wx_string>NSW</wx_string>
<sky_condition sky_cover="SCT" cloud_base_ft_agl="3000" />
</forecast>
</TAF>
</data>
</response>
我POJO类看起来是这样的:
@XmlRootElement(name = "response")
public class Response {
@XmlElement private List<Taf> data; // I don't need any other contents of this element
public List<Taf> getData() {
return data;
}
public void setData(List<Taf> data) {
this.data = data;
}
}
@XmlRootElement(name = "TAF")
public class Taf {
@XmlElement(name = "raw_text") private String raw_text;
@XmlElement(name = "station_id") private String station_id; // ICAO
@XmlElement(name = "issue_time") private Date issue_time;
@XmlElement(name = "bulletin_time") private Date bulletin_time;
@XmlElement(name = "valid_time_from") private Date valid_time_from;
@XmlElement(name = "valid_time_to") private Date valid_time_to;
@XmlElement(name = "remarks") private String remarks;
@XmlElement(name = "latitude") private Double latitude;
@XmlElement(name = "longitude") private Double longitude;
@XmlElement(name = "elevation_m") private Double elevation_m;
@XmlElement(name = "forecast", type = Forecast.class) private List<Forecast> forecast;
// getters and setters
}
@XmlRootElement(name = "forecast")
public class Forecast {
@XmlElement(name = "fcst_time_from") private Date fcst_time_from;
@XmlElement(name = "fcst_time_to") private Date fcst_time_to;
@XmlElement(name = "wind_dir_degrees") private Integer wind_dir_degrees;
@XmlElement(name = "wind_speed_kt") private Integer wind_speed_kt;
@XmlElement(name = "visibility_statute_mi") private Double visibility_statute_mi;
@XmlElement(name = "wx_string") private String wx_string;
@XmlElement(name = "sky_condition", type = SkyCondition.class) private List<SkyCondition> sky_condition;
// getters and setters
}
@XmlRootElement(name = "sky_condition")
public class SkyCondition {
@XmlAttribute(name = "sky_cover") private String sky_cover;
@XmlAttribute(name = "cloud_base_ft_agl") private Integer cloud_base_ft_agl;
// getters and setters
}
现在我的服务有一个简单的方法:
public List<Taf> getTafsForICAO(String icao) {
RestTemplate restTemplate = new RestTemplate();
Response resp = restTemplate.getForObject(tafUrl+icao, Response.class);
return resp.getData();
}
如果我忽略嵌套的forecast
元素,则所有内容都正确解析。但我需要这些嵌套元素,如果我运行一切,因为它是,我得到以下异常:
Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error:
Can not construct instance of airports.models.taf.Forecast:
no String-argument constructor/factory method to deserialize from String value ('2017-10-17T12:00:00Z'); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of airports.models.taf.Forecast: no String-argument constructor/factory method to deserialize from String value ('2017-10-17T12:00:00Z')
at [Source: [email protected]; line: 21, column: 45] (through reference chain: airports.models.taf.Response["data"]->java.util.ArrayList[0]->airports.models.taf.Taf["forecast"]->java.util.ArrayList[0])
它看起来像解析器看到forecast
第一个子元素,这是fcst_time_from
了它的内容,并试图将日期反序列化为Forecast
对象。我不知道为什么。也许我错过了一些简单的东西?预先感谢您的帮助。
UPDATE
我有点接近这个问题。嵌套的TAF
元素在response
元素中被正确解析,因为它们被包装在data
元素中。不幸的是,TAF
内部没有包含forecast
标签列表的包装元素。我为Forecast
类创建了一个带String参数的构造函数,现在它将嵌入元素(fcst_time_from,fcst_time_to等)解析为Forcast
对象。有没有办法来声明这个内部列表没有包装元素?
更新2
一些测试后,我想通了problewm是严格把解析的元素展开列表。我不知道为什么,但如果我宣布我的Result
类这样的,而不是显示更高的声明:
@XmlRootElement(name = "response")
public class Response {
@XmlElementWrapper(name = "data")
@XmlElement(name = "TAF")
private List<Taf> tafs;
public List<Taf> getTafs() {
return tafs;
}
public void setTafs(List<Taf> tafs) {
this.tafs = tafs;
}
}
它不工作。没有TAF元素被解析。这似乎是解析器迫使所有列表被包装。不幸的是,我在REST输出中打开了forecast
列表。我该如何处理这个问题?我看到@Element(inline = true)
注释的参数,但@XmlElement
没有这样的事情。我可以以某种方式强制RestTemplate本身的解包列表?
OMG
两天的努力找出我需要一条线来解决这个问题。所以......从解析器的角度来看,所有这些@XmlElement
注解都是无用的。仅当我想将对象作为REST服务输出时才使用它们。为了告诉任何解析器,我需要使用@JacksonXmlElementWrapper
注释。确切的解决方案是:
@XmlRootElement(name = "TAF")
public class Taf {
@XmlElement(name = "raw_text") private String raw_text;
@XmlElement(name = "station_id") private String station_id; // ICAO
@XmlElement(name = "issue_time") private Date issue_time;
@XmlElement(name = "bulletin_time") private Date bulletin_time;
@XmlElement(name = "valid_time_from") private Date valid_time_from;
@XmlElement(name = "valid_time_to") private Date valid_time_to;
@XmlElement(name = "remarks") private String remarks;
@XmlElement(name = "latitude") private Double latitude;
@XmlElement(name = "longitude") private Double longitude;
@XmlElement(name = "elevation_m") private Double elevation_m;
@JacksonXmlElementWrapper(useWrapping = false)
@XmlElement(name = "forecast") private List<Forecast> forecast;
// getters and setters
}
和
@XmlRootElement(name = "forecast")
public class Forecast {
@XmlElement(name = "fcst_time_from") private Date fcst_time_from;
@XmlElement(name = "fcst_time_to") private Date fcst_time_to;
@XmlElement(name = "wind_dir_degrees") private Integer wind_dir_degrees;
@XmlElement(name = "wind_speed_kt") private Integer wind_speed_kt;
@XmlElement(name = "visibility_statute_mi") private Double visibility_statute_mi;
@XmlElement(name = "ex_string") private String wx_string;
@JacksonXmlElementWrapper(useWrapping = false)
@XmlElement(name = "sky_condition") private List<SkyCondition> sky_condition;
// getters and setters
}
就是这样。
请先修复主要问题,然后我们可以看到......主要问题是:您的RestTemplate无法将'2017-10-17T12:00:00Z'解析/反序列化为'java.util。日期'!有关解决方案,请参阅:https://stackoverflow.com/q/21355450/592355('ObjectMapper.setDateFormat()'!) – xerx593
@ xerx593不,不是。它将'2017-10-17T12:00:00Z'解析为'java.utill.Date',没有问题。当我注释列表预测Taf对象正确解析(并且它们包含日期字段)。此错误表示它尝试将此日期字符串反序列化为Forecast对象。 –
Yaerius