Ошибка десериализации Apache camel xml

Я пытаюсь десериализовать xml с помощью apache camel jackson xml, и происходит что-то странное, чему у меня нет объяснения. Вот xml, который я пытаюсь десериализовать (это простой файл xmltv xml):

<?xml version="1.0" encoding="UTF-8"?>
<tv>
  <programme start="20210102000300 +0000" stop="20210102003000 +0000" channel="XTV100005403" recordable="Y" npvrenable="Y" id="SH032096260000.20210102000300.44345" type="program">
     <title lang="en">Barbados Ninja Throwdown</title>
     <desc lang="en">Contestants compete to complete a challenging obstacle course the fastest.</desc>
     <credits>
        <actor nameId="1288485">Wayne Simmons</actor>
     </credits>
     <date>20190427</date>
     <category>Reality</category>
     <category>Action sports</category>
     <category>Action</category>
     <category>Adventure</category>
     <releaseType>TV</releaseType>
     <extentionInfo>
        <key>releaseStatus</key>
        <value>1</value>
     </extentionInfo>
  </programme>
</tv>

Вот мои POJO:

Tv.java

@XmlRootElement(name = "tv")
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class Tv {

  @XmlElement(name = "programme")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Programme> programmes = new ArrayList<>();

}

Programme.java

@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class Programme {

  @XmlAttribute(name = "id")
  @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
  private String id;

  @XmlAttribute(name = "type")
  @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
  private String type;

  @XmlAttribute(name = "start", required = true)
  @JsonDeserialize(using = OffsetDateTimeDeserializer.class)
  private OffsetDateTime start;

  @XmlAttribute(name = "stop")
  @JsonDeserialize(using = OffsetDateTimeDeserializer.class)
  private OffsetDateTime stop;

  @XmlAttribute(name = "pdc-start")
  @JsonDeserialize(using = OffsetDateTimeDeserializer.class)
  private OffsetDateTime pdcStart;

  @XmlAttribute(name = "vps-start")
  @JsonDeserialize(using = OffsetDateTimeDeserializer.class)
  private OffsetDateTime vpsStart;

  @XmlAttribute(name = "showview")
  @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
  private String showview;

  @XmlAttribute(name = "videoplus")
  @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
  private String videoplus;

  @XmlAttribute(name = "channel", required = true)
  @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
  private String channel;

  @XmlAttribute(name = "clumpidx")
  @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
  private String clumpidx;

  @XmlElement(name = "title", required = true)
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Label> titles;

  @XmlElement(name = "sub-title")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Label> subTitle;

  @XmlElement(name = "desc")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Label> descriptions;

  @XmlElement(name = "credits")
  private Credits credits;

  private String date;

  @XmlElement(name = "category")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Label> categories;

  @XmlElement(name = "keyword")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Label> keywords;

  private Label language;

  @XmlElement(name = "orig-language")
  private Label origLanguage;

  private Length length;

  @XmlElement(name="icons")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Icon> icons;

  @XmlElement(name = "url")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> urls;

  @XmlElement(name = "country")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Label> countries;

  @XmlElement(name = "episode-num")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<EpisodeNum> episodeNumbers;

  private Video video;

  private Audio audio;

  @XmlElement(name = "previously-shown")
  private PreviouslyShown previouslyShown;

  private Label premiere;

  @XmlElement(name = "last-chance")
  private Label lastChance;

  @XmlElement(name = "new")
  private Label isNew;

  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Subtitles> subtitles;

  @XmlElement(name = "rating")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Rating> ratings;

  @XmlElement(name = "star-rating")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<StarRating> starRatings;

  @XmlElement(name = "review")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<Review> reviews;
  
}

Credits.java

@Data
public class Credits {
  @XmlElement(name = "director")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> directors;

  @XmlElement(name = "actor")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> actors;

  @XmlElement(name = "writer")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> writers;

  @XmlElement(name = "adapter")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> adapters;

  @XmlElement(name = "producer")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> producers;

  @XmlElement(name = "composer")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> composers;

  @XmlElement(name = "editor")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> editors;

  @XmlElement(name = "presenter")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> presenters;

  @XmlElement(name = "commentator")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> commentators;

  @XmlElement(name = "guest")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> guests;
}

Остальные POJO не важны. Итак, вот конфигурация маршрута:

@Override
  public void configure() throws Exception {
    final JacksonXMLDataFormat dataFormat = new JacksonXMLDataFormat();
    dataFormat.setUnmarshalType(Tv.class);

    from("file:///someLocation")
        .routeId(getClass().getSimpleName())
        .autoStartup(true)
        .unmarshal(dataFormat)
        .process("someProcessorBean")

  }

С этой настройкой и xml, который я предоставил в начале, возникает следующее исключение:

Мне потребовалось много времени, чтобы понять, что это значит. Таким образом, кажется, что он принимает закрывающий тег как конец тега, а после этого пытается создать новый экземпляр программы из значения тега и терпит неудачу, потому что не знает, как это сделать. Чтобы доказать это для себя, я переместил тег в конец тега, чтобы xml выглядел следующим образом:

На этот раз, когда я запускаю приложение, XML десериализуется правильно без каких-либо исключений. Так может кто-нибудь объяснить мне, почему это так и я где-то ошибся?

<?xml version="1.0" encoding="UTF-8"?>
<tv>
  <programme start="20210102000300 +0000" stop="20210102003000 +0000" channel="XTV100005403" recordable="Y" npvrenable="Y" id="SH032096260000.20210102000300.44345" type="program">
     <title lang="en">Barbados Ninja Throwdown</title>
     <desc lang="en">Contestants compete to complete a challenging obstacle course the fastest.</desc>
     <date>20190427</date>
     <category>Reality</category>
     <category>Action sports</category>
     <category>Action</category>
     <category>Adventure</category>
     <releaseType>TV</releaseType>
     <extentionInfo>
        <key>releaseStatus</key>
        <value>1</value>
     </extentionInfo>
     <credits>
        <actor nameId="1288485">Wayne Simmons</actor>
     </credits>
  </programme>
</tv>

Я использую apache camel 2.25.3 и, соответственно, ту же версию camel-jacksonxml.

Редактировать:

Выделить проблему удалось только Джексону:

Это приводит к тому же исключению.

 JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
 jacksonXmlModule.setDefaultUseWrapper(false);
 ObjectMapper objectMapper = new XmlMapper(jacksonXmlModule);
 objectMapper.registerModule(new JaxbAnnotationModule());
 objectMapper.readValue(new File("xmlFilePath"), Tv.class);

Итак, я выяснил, что вызывает это исключение, хотя я не совсем уверен, почему это так. После сеанса отладки сопоставителя объектов Джексона я обнаружил, что проблема в атрибуте nameId тега актера. И кажется, десериализатор не может решить, как это сделать, когда у меня есть:


person Hristo Angelov    schedule 31.12.2020    source источник


Ответы (1)


Итак, решение, которое я нашел (которое я не уверен, является наиболее правильным), - это создать еще один pojo CreditsElement.java:

  @XmlElement(name = "actor")
  @JacksonXmlElementWrapper(useWrapping = false)
  private List<String> actors;

Я не включаю атрибут nameId, потому что он мне не нужен. Помимо этого решения, есть ли лучший способ сопоставить его без создания другого класса и использования свойства List?

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class CreditsElement {

  @XmlValue
  private String value;
}

com.fasterxml.jackson.databind.exc.MismatchedInputException: невозможно создать экземпляр _6_ (хотя существует хотя бы один создатель): нет конструктора аргумента String / фабричного метода для десериализации из значения String ('20190427') в [Источник: (BufferedInputStream ); строка: 9, столбец: 20] (через цепочку ссылок: com.azdio.mdw.ingest.epg.xmltv.common.domain.Tv [программа] - ›java.util.ArrayList [1]) в com.fasterxml.jackson .databind.exc.MismatchedInputException.from (MismatchedInputException.java:63) в com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch (DeserializationContext.java:1429) в com.fasterxml.jackson.databind.DeselerialContext (DetextResponse) : 1059) в com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks (ValueInstantiator.java:371) в com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromStringstan (StdValueInstantiator. fastxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString (BeanDeserializerBase.java:1373) в com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther (BeanDeserializer.java:serson.dx.java:171.dx.java: BeanDeserializer.deserialize (BeanDeserializer.java:161) в com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize (WrapperHandlingDeserializer.java:114) по адресу com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserializer.deserializer.com. .jackson.databind.deser.std.CollectionDeserializer.deserialize (CollectionDeserializer.java:245) в com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize (CollectionDeserializer.java:27) в com.fasterxml.jackson.databind .deser.impl.MethodProperty.deserializeAndSet (MethodProperty.java:129) по адресу com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize (BeanDeserializer.java:288) по адресу com.fasterxml.jackser. (BeanDeserializer.java:151) в com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize (WrapperHandlingDeserializer.java:114) в com.fasterxml.jackson.databind.ObjectMapper._readMap com.fasterxml.jackson.da tabind.ObjectMapper.readValue (ObjectMapper.java:3242) по адресу org.apache.camel.component.jacksonxml.JacksonXMLDataFormat.unmarshal (JacksonXMLDataFormat.java:193) по адресу org.apache.camel.processor.Processor.Unava: 69) на org.apache.camel.processor. RedeliveryErrorHandler.process (RedeliveryErrorHandler.java:548) по адресу org.apache.camel.processor.CamelInternalProcessor.process (CamelInternalProcessor.java:201) по адресу org.apache.camel.processor.Pipeline.java: org.apache.camel.processor. .apache.camel.processor.Pipeline.process (Pipeline.java:101) в org.apache.camel.processor.CamelInternalProcessor.process (CamelInternalProcessor.java:201) в org.apache.camel.component.file.GenericFileConschangemer (GenericFileConsumer.java:454) в org.apache.camel.component.file.GenericFileConsumer.processBatch (GenericFileConsumer.java:223) в org.apache.camel.component.file.GenericFileConsumer.java (GenericFileConsumer.java) at GenericFileConsumer.java (GenericFileConsumer.java) org.apache.camel.impl.ScheduledPollConsumer.doRun (ScheduledPollConsumer.java:174) в org.apache.camel.impl.ScheduledPollConsumer.run (ScheduledPollConsumer.java:101)

person Hristo Angelov    schedule 31.12.2020