简体   繁体   中英

Cannot deserialize ArrayList object out of String from nested XML to Java POJO using Jackson

I have a REST service that calls an external endpoint which returns XML response.

Project dependencies are basically Lombok, spring starter web and jackson.

<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
  <version>2.13.3</version>
</dependency>

Here is the current XML response received once the endpoint is called:

<?xml version="1.0" encoding="UTF-8"?>
<Publication_MarketDocument xmlns="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0">
   <mRID>032af514c4a34ede9911c84cda33a547</mRID>
   <revisionNumber>1</revisionNumber>
   <type>A44</type>
   <sender_MarketParticipant.mRID codingScheme="A01">10X1001A1001A450</sender_MarketParticipant.mRID>
   <sender_MarketParticipant.marketRole.type>A32</sender_MarketParticipant.marketRole.type>
   <receiver_MarketParticipant.mRID codingScheme="A01">10X1001A1001A450</receiver_MarketParticipant.mRID>
   <receiver_MarketParticipant.marketRole.type>A33</receiver_MarketParticipant.marketRole.type>
   <createdDateTime>2022-09-01T12:15:32Z</createdDateTime>
   <period.timeInterval>
      <start>2015-12-31T23:00Z</start>
      <end>2016-01-02T23:00Z</end>
   </period.timeInterval>
   <TimeSeries>
      <mRID>1</mRID>
      <businessType>A62</businessType>
      <in_Domain.mRID codingScheme="A01">10YCZ-CEPS-----N</in_Domain.mRID>
      <out_Domain.mRID codingScheme="A01">10YCZ-CEPS-----N</out_Domain.mRID>
      <currency_Unit.name>EUR</currency_Unit.name>
      <price_Measure_Unit.name>MWH</price_Measure_Unit.name>
      <curveType>A01</curveType>
      <Period>
         <timeInterval>
            <start>2015-12-31T23:00Z</start>
            <end>2016-01-01T23:00Z</end>
         </timeInterval>
         <resolution>PT60M</resolution>
         <Point>
            <position>1</position>
            <price.amount>16.50</price.amount>
         </Point>
         <Point>
            <position>2</position>
            <price.amount>15.50</price.amount>
         </Point>
         <Point>
            <position>3</position>
            <price.amount>14.00</price.amount>
         </Point>
         <Point>
            <position>4</position>
            <price.amount>10.01</price.amount>
         </Point>
         <Point>
            <position>5</position>
            <price.amount>8.97</price.amount>
         </Point>
         <Point>
            <position>6</position>
            <price.amount>12.23</price.amount>
         </Point>
         <Point>
            <position>7</position>
            <price.amount>12.10</price.amount>
         </Point>
         <Point>
            <position>8</position>
            <price.amount>14.00</price.amount>
         </Point>
         <Point>
            <position>9</position>
            <price.amount>5.00</price.amount>
         </Point>
         <Point>
            <position>10</position>
            <price.amount>10.01</price.amount>
         </Point>
         <Point>
            <position>11</position>
            <price.amount>14.50</price.amount>
         </Point>
         <Point>
            <position>12</position>
            <price.amount>5.00</price.amount>
         </Point>
         <Point>
            <position>13</position>
            <price.amount>6.00</price.amount>
         </Point>
         <Point>
            <position>14</position>
            <price.amount>11.05</price.amount>
         </Point>
         <Point>
            <position>15</position>
            <price.amount>21.00</price.amount>
         </Point>
         <Point>
            <position>16</position>
            <price.amount>25.00</price.amount>
         </Point>
         <Point>
            <position>17</position>
            <price.amount>31.20</price.amount>
         </Point>
         <Point>
            <position>18</position>
            <price.amount>34.02</price.amount>
         </Point>
         <Point>
            <position>19</position>
            <price.amount>35.00</price.amount>
         </Point>
         <Point>
            <position>20</position>
            <price.amount>34.50</price.amount>
         </Point>
         <Point>
            <position>21</position>
            <price.amount>34.03</price.amount>
         </Point>
         <Point>
            <position>22</position>
            <price.amount>30.00</price.amount>
         </Point>
         <Point>
            <position>23</position>
            <price.amount>28.13</price.amount>
         </Point>
         <Point>
            <position>24</position>
            <price.amount>21.80</price.amount>
         </Point>
      </Period>
   </TimeSeries>
   <TimeSeries>
      <mRID>2</mRID>
      <businessType>A62</businessType>
      <in_Domain.mRID codingScheme="A01">10YCZ-CEPS-----N</in_Domain.mRID>
      <out_Domain.mRID codingScheme="A01">10YCZ-CEPS-----N</out_Domain.mRID>
      <currency_Unit.name>EUR</currency_Unit.name>
      <price_Measure_Unit.name>MWH</price_Measure_Unit.name>
      <curveType>A01</curveType>
      <Period>
         <timeInterval>
            <start>2016-01-01T23:00Z</start>
            <end>2016-01-02T23:00Z</end>
         </timeInterval>
         <resolution>PT60M</resolution>
         <Point>
            <position>1</position>
            <price.amount>0.01</price.amount>
         </Point>
         <Point>
            <position>2</position>
            <price.amount>1.00</price.amount>
         </Point>
         <Point>
            <position>3</position>
            <price.amount>0.01</price.amount>
         </Point>
         <Point>
            <position>4</position>
            <price.amount>0.01</price.amount>
         </Point>
         <Point>
            <position>5</position>
            <price.amount>2.01</price.amount>
         </Point>
         <Point>
            <position>6</position>
            <price.amount>1.00</price.amount>
         </Point>
         <Point>
            <position>7</position>
            <price.amount>0.01</price.amount>
         </Point>
         <Point>
            <position>8</position>
            <price.amount>1.00</price.amount>
         </Point>
         <Point>
            <position>9</position>
            <price.amount>5.11</price.amount>
         </Point>
         <Point>
            <position>10</position>
            <price.amount>22.00</price.amount>
         </Point>
         <Point>
            <position>11</position>
            <price.amount>41.29</price.amount>
         </Point>
         <Point>
            <position>12</position>
            <price.amount>51.08</price.amount>
         </Point>
         <Point>
            <position>13</position>
            <price.amount>51.09</price.amount>
         </Point>
         <Point>
            <position>14</position>
            <price.amount>61.93</price.amount>
         </Point>
         <Point>
            <position>15</position>
            <price.amount>50.00</price.amount>
         </Point>
         <Point>
            <position>16</position>
            <price.amount>53.04</price.amount>
         </Point>
         <Point>
            <position>17</position>
            <price.amount>100.00</price.amount>
         </Point>
         <Point>
            <position>18</position>
            <price.amount>64.83</price.amount>
         </Point>
         <Point>
            <position>19</position>
            <price.amount>58.02</price.amount>
         </Point>
         <Point>
            <position>20</position>
            <price.amount>32.29</price.amount>
         </Point>
         <Point>
            <position>21</position>
            <price.amount>35.08</price.amount>
         </Point>
         <Point>
            <position>22</position>
            <price.amount>22.00</price.amount>
         </Point>
         <Point>
            <position>23</position>
            <price.amount>22.00</price.amount>
         </Point>
         <Point>
            <position>24</position>
            <price.amount>16.00</price.amount>
         </Point>
      </Period>
   </TimeSeries>
</Publication_MarketDocument>

And below are all the Java classes that I am using in order to map the above XML to POJOs.

PublicationMarketDocument class

@Data
public class PublicationMarketDocument {
    @JsonProperty("revisionNumber")
    private String revisionNumber;
    @JsonProperty("period.timeInterval")
    private TimeInterval timeInterval;
    @JsonProperty("TimeSeries")
    private List<TimeSeries> timeSeries;
}

TimeInterval class

@Data
public class TimeInterval {
    @JsonProperty("start")
    private String start;
    @JsonProperty("end")
    private String end;
}

TimeSeries class

@Data
public class TimeSeries {
    @JsonProperty("businessType")
    private String businessType;
    @JsonProperty("in_Domain.mRID")
    private String inDomain;
    @JsonProperty("out_Domain.mRID")
    private String outDomain;
    @JsonProperty("currency_Unit.name")
    private String currencyName;
    @JsonProperty("price_Measure_Unit.name")
    private String priceMeasureUnitName;
    @JsonProperty("curveType")
    private String curveType;
    @JsonProperty("Period")
    private Period period;
}

Period class

@Data
public class Period {

    @JsonProperty("timeInterval")
    private TimeInterval timeInterval;
    @JsonProperty("resolution")
    private String resolution;
    @JsonProperty("Point")
    private List<Point> point;
}

Point class

@Data
public class Point {
    @JsonProperty("position")
    String position;
    @JsonProperty("price.amount")
    String priceAmount;
}

Here is the controller class used to actually invoke the external API:

@RestController
@RequestMapping("/api/v1/")
@Slf4j
public class FetchController {

    @GetMapping(value = "day-ahead-prices", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<PublicationMarketDocument> getDayAheadPrices() {

        String localUrl = URL + "&periodStart=" + pStart + "&periodEnd=" + pEnd;

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<PublicationMarketDocument> response = restTemplate.getForEntity(localUrl, PublicationMarketDocument.class);

        return new ResponseEntity<>(response.getBody(), HttpStatus.OK);

    }
}

Here is the error received on app initiliazation:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.RestClientException: Error while extracting response for type [class com.example.openvpp.models.MarketDataModel] and content type [text/xml]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.example.openvpp.models.TimeSeries` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('1'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.example.openvpp.models.TimeSeries` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('1')
 at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 16, column: 10] (through reference chain: com.example.openvpp.models.MarketDataModel["TimeSeries"]->java.util.ArrayList[0])] with root cause

Below approximate result is obtained only if we do not have the TimeSeries and Point fields as Lists in the caller classes. Once we wrap them as List<>, the problem occurs.

{
    "revisionNumber": "1",
    "period.timeInterval": {
        "start": "2015-12-31T23:00Z",
        "end": "2016-01-01T23:00Z"
    },
    "TimeSeries": {
        "businessType": "A62",
        "in_Domain.mRID": "10YCZ-CEPS-----N",
        "out_Domain.mRID": "10YCZ-CEPS-----N",
        "currency_Unit.name": "EUR",
        "price_Measure_Unit.name": "MWH",
        "curveType": "A01",
        "Period": {
            "timeInterval": {
                "start": "2015-12-31T23:00Z",
                "end": "2016-01-01T23:00Z"
            },
            "resolution": "PT60M",
            "Point": {
                "position": "24",
                "price.amount": "21.80"
            }
        }
    }
}

The main problem that I am facing is deserializing the nested XML fields to TimeSeries and Point List Objects. Already tried adding @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) to both of them with no success.

Also tried this annotation @JsonDeserialize(as=ArrayList.class, contentAs=Point.class) however error remains the same.

Is there an elegant way to do it at the moment and is this a drawback of jackson library itself?

I do not have control over the external XML endpoint. Furthermore I do not control an ObjectMapper instance since I want Jackson to do the mapping of the XML to Java POJOs entirely.

PS Adding here the final results obtained after @qdoot advised of using the @JacksonXmlElementWrapper(useWrapping = false) annotation. Hope this helps for someone looking at this in the future.

{
    "revisionNumber": "1",
    "period.timeInterval": {
        "start": "2015-12-31T23:00Z",
        "end": "2016-01-02T23:00Z"
    },
    "TimeSeries": [
        {
            "businessType": "A62",
            "in_Domain.mRID": "10YCZ-CEPS-----N",
            "out_Domain.mRID": "10YCZ-CEPS-----N",
            "currency_Unit.name": "EUR",
            "price_Measure_Unit.name": "MWH",
            "curveType": "A01",
            "Period": {
                "timeInterval": {
                    "start": "2015-12-31T23:00Z",
                    "end": "2016-01-01T23:00Z"
                },
                "resolution": "PT60M",
                "Point": [
                    {
                        "position": "1",
                        "price.amount": "16.50"
                    },
                    {
                        "position": "2",
                        "price.amount": "15.50"
                    },
                    {
                        "position": "3",
                        "price.amount": "14.00"
                    },
                    {
                        "position": "4",
                        "price.amount": "10.01"
                    },
                    {
                        "position": "5",
                        "price.amount": "8.97"
                    },
                    {
                        "position": "6",
                        "price.amount": "12.23"
                    },
                    {
                        "position": "7",
                        "price.amount": "12.10"
                    },
                    {
                        "position": "8",
                        "price.amount": "14.00"
                    },
                    {
                        "position": "9",
                        "price.amount": "5.00"
                    },
                    {
                        "position": "10",
                        "price.amount": "10.01"
                    },
                    {
                        "position": "11",
                        "price.amount": "14.50"
                    },
                    {
                        "position": "12",
                        "price.amount": "5.00"
                    },
                    {
                        "position": "13",
                        "price.amount": "6.00"
                    },
                    {
                        "position": "14",
                        "price.amount": "11.05"
                    },
                    {
                        "position": "15",
                        "price.amount": "21.00"
                    },
                    {
                        "position": "16",
                        "price.amount": "25.00"
                    },
                    {
                        "position": "17",
                        "price.amount": "31.20"
                    },
                    {
                        "position": "18",
                        "price.amount": "34.02"
                    },
                    {
                        "position": "19",
                        "price.amount": "35.00"
                    },
                    {
                        "position": "20",
                        "price.amount": "34.50"
                    },
                    {
                        "position": "21",
                        "price.amount": "34.03"
                    },
                    {
                        "position": "22",
                        "price.amount": "30.00"
                    },
                    {
                        "position": "23",
                        "price.amount": "28.13"
                    },
                    {
                        "position": "24",
                        "price.amount": "21.80"
                    }
                ]
            }
        },
        {
            "businessType": "A62",
            "in_Domain.mRID": "10YCZ-CEPS-----N",
            "out_Domain.mRID": "10YCZ-CEPS-----N",
            "currency_Unit.name": "EUR",
            "price_Measure_Unit.name": "MWH",
            "curveType": "A01",
            "Period": {
                "timeInterval": {
                    "start": "2016-01-01T23:00Z",
                    "end": "2016-01-02T23:00Z"
                },
                "resolution": "PT60M",
                "Point": [
                    {
                        "position": "1",
                        "price.amount": "0.01"
                    },
                    {
                        "position": "2",
                        "price.amount": "1.00"
                    },
                    {
                        "position": "3",
                        "price.amount": "0.01"
                    },
                    {
                        "position": "4",
                        "price.amount": "0.01"
                    },
                    {
                        "position": "5",
                        "price.amount": "2.01"
                    },
                    {
                        "position": "6",
                        "price.amount": "1.00"
                    },
                    {
                        "position": "7",
                        "price.amount": "0.01"
                    },
                    {
                        "position": "8",
                        "price.amount": "1.00"
                    },
                    {
                        "position": "9",
                        "price.amount": "5.11"
                    },
                    {
                        "position": "10",
                        "price.amount": "22.00"
                    },
                    {
                        "position": "11",
                        "price.amount": "41.29"
                    },
                    {
                        "position": "12",
                        "price.amount": "51.08"
                    },
                    {
                        "position": "13",
                        "price.amount": "51.09"
                    },
                    {
                        "position": "14",
                        "price.amount": "61.93"
                    },
                    {
                        "position": "15",
                        "price.amount": "50.00"
                    },
                    {
                        "position": "16",
                        "price.amount": "53.04"
                    },
                    {
                        "position": "17",
                        "price.amount": "100.00"
                    },
                    {
                        "position": "18",
                        "price.amount": "64.83"
                    },
                    {
                        "position": "19",
                        "price.amount": "58.02"
                    },
                    {
                        "position": "20",
                        "price.amount": "32.29"
                    },
                    {
                        "position": "21",
                        "price.amount": "35.08"
                    },
                    {
                        "position": "22",
                        "price.amount": "22.00"
                    },
                    {
                        "position": "23",
                        "price.amount": "22.00"
                    },
                    {
                        "position": "24",
                        "price.amount": "16.00"
                    }
                ]
            }
        }
    ]
}

You might try @JacksonXmlElementWrapper

   @JacksonXmlElementWrapper(useWrapping=false)
   private List<Point> point;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM