2017-10-17 30 views
0

我想消費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本身的解包列表?

+1

請先修復主要問題,然後我們可以看到......主要問題是:您的RestTemplate無法將'2017-10-17T12:00:00Z'解析/反序列化爲'java.util。日期'!有關解決方案,請參閱:https://stackoverflow.com/q/21355450/592355('ObjectMapper.setDateFormat()'!) – xerx593

+0

@ xerx593不,不是。它將'2017-10-17T12:00:00Z'解析爲'java.utill.Date',沒有問題。當我註釋列表預測Taf對象正確解析(並且它們包含日期字段)。此錯誤表示它嘗試將此日期字符串反序列化爲Forecast對象。 – Yaerius

回答

1

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 
} 

就是這樣。