Я пытаюсь десериализовать 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 тега актера. И кажется, десериализатор не может решить, как это сделать, когда у меня есть: