#java #xml #xml-parsing #jaxb #moxy
#java #xml #xml-синтаксический анализ #jaxb #moxy
Вопрос:
Я реализую простой анализатор xml и столкнулся с проблемой: при инициализации JAXBContext возникает исключение.
Вот мой код (возможно, слишком много для этого вопроса, но я постарался включить только важные части):
Сам анализатор:
package com.andreiyusupau.jaxbparser.parser;
import com.andreiyusupau.jaxbparser.model.Parent;
import com.andreiyusupau.jaxbparser.model.Root;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.util.Collection;
public class JaxbParser {
public Collection<Parent> parse(String inputXml) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(new File(inputXml));
return root.getElements();
}
}
Главная:
public class Main {
public static final String FILE_NAME = "data.xml";
public static void main(String[] args) throws JAXBException {
JaxbParser jaxbParser = new JaxbParser();
Collection<Parent> elements= jaxbParser.parse(FILE_NAME);
for (Parent element : elements) {
System.out.println(element.toString());
}
}
}
Классы (геттеры, сеттеры и toString скрыты):
import javax.xml.bind.annotation.*;
import java.util.List;
@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElements({
@XmlElement(name = "ChildA", type = ChildA.class),
@XmlElement(name = "ChildB", type = ChildB.class),
})
private List<Parent> elements;
public Root() {
}
}
import org.eclipse.persistence.oxm.annotations.XmlPath;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
@XmlTransient
@XmlSeeAlso({ChildA.class, ChildB.class})
public class Parent {
@XmlAttribute
private int id;
@XmlElement(name = "name")
private String name;
@XmlElement(name = "parameter")
private String parameter;
@XmlPath("parameter/@parameterAttr")
private String parameterAttribute;
@XmlPath("similar/a/text()")
private int a;
@XmlPath("similar/b/text()")
private int b;
@XmlPath("different/similar/text()")
private String similar;
@XmlPath("different/similar/@similarAttr")
private String similarAttribute;
public Parent() {
}
}
import org.eclipse.persistence.oxm.annotations.XmlPath;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "childA")
public class ChildA extends Parent {
@XmlPath("different/differentA/text()")
private String differentA;
@XmlPath("different/differentA/@attrA")
private String differentAttributeA;
public ChildA() {
}
}
import org.eclipse.persistence.oxm.annotations.XmlPath;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "childB")
public class ChildB extends Parent {
@XmlPath("different/differentB1/text()")
private String differentB1;
@XmlPath("different/differentB1/@attrB1")
private String differentAttributeB1;
@XmlPath("different/differentB2/text()")
private String differentB2;
@XmlPath("different/differentB2/@attrB2")
private String differentAttributeB2;
public ChildB() {
}
}
and finally an xml file itself:
<?xml version="1.1" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation = "schema.xsd">
<childA id="ID-1">
<name>Name</name>
<parameter parameterAttr="a">b</parameter>
<similarGroup>
<a>1</a>
<b>2</b>
</similarGroup>
<different>
<similar similarAttr="n">2</similar>
<differentA attrA="n">100</differentA>
</different>
</childA>
<childB id="ID-2">
<name>Name</name>
<parameter parameterAttr="c">d</parameter>
<similarGroup>
<a>6</a>
<b>8</b>
</similarGroup>
<different>
<similar similarAttr="g">7</similar>
<differentB1 attrB1="5">100</differentB1>
<differentB2>100</differentB2>
</different>
</childB>
</root>
и зависимости в POM xml:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>3.0.0-M1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
jaxb.properties
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Компиляция и запуск этого кода приводит к следующему исключению:
Exception in thread "main" java.lang.NoClassDefFoundError: jakarta/xml/bind/JAXBContext
at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3166)
at java.base/java.lang.Class.getMethodsRecursive(Class.java:3307)
at java.base/java.lang.Class.getMethod0(Class.java:3293)
at java.base/java.lang.Class.getMethod(Class.java:2106)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:249)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:240)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:345)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:691)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:632)
at com.andreiyusupau.jaxbparser.parser.JaxbParser.parse(JaxbParser.java:15)
at com.andreiyusupau.jaxbparser.Main.main(Main.java:15)
Caused by: java.lang.ClassNotFoundException: jakarta.xml.bind.JAXBContext
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 12 more
Может быть, кто-нибудь знает, как я могу это решить?
Обновить:
После замены jakarta.xml.bind-api
на у jaxb-api
меня есть следующее исключение:
Exception in thread "main" javax.xml.bind.JAXBException: ClassCastException: attempting to cast jar:file:/C:/Users/Nevermind/.m2/repository/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar!/javax/xml/bind/JAXBContext.class to jar:file:/C:/Users/Nevermind/.m2/repository/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar!/javax/xml/bind/JAXBContext.class. Please make sure that you are specifying the proper ClassLoader.
at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:157)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:300)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:286)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:391)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
at com.andreiyusupau.jaxbparser.parser.JaxbParser.parse(JaxbParser.java:15)
at com.andreiyusupau.jaxbparser.Main.main(Main.java:15)
Исключение выдается в строке:
JAXBContext jc = JAXBContext.newInstance(Root.class);
Есть предложения?
Комментарии:
1. какую версию JDK вы используете? Я только что попробовал ваш исходный код в модуле быстрого запуска Maven с JDK 11.0.5 и IntelliJ, и он не жалуется на то, что классы не найдены.
2. @P3trur0 Я использую jdk-11.0.8 Amazon Coretto.
Ответ №1:
Я предлагаю заменить зависимость
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
с помощью
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
jakarta.xml.bind
происходит из Jakarta EE и org.glassfish.jaxb
происходит из более старой Java EE.
Комментарии:
1. Спасибо за ваш ответ. Я следовал вашим рекомендациям, но теперь он выдает другое исключение. Пожалуйста, посмотрите Обновленный вопрос, может быть, у вас есть какие-либо предложения?
2. Обновлен ответ. Не могли бы вы попробовать зависимость от jaxb-api?
3. Обновлен код. То же исключение. Может быть, проблема связана с JDK11 или с Eclipse Moxy?
Ответ №2:
Сделайте mvn dependency:tree
(или mvn help:effective-pom
), чтобы увидеть, какие зависимости заканчиваются на вашем пути к классу.
Попробуйте использовать эти:
<!-- XML -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<scope>runtime</scope>
<version>2.3.3</version>
</dependency>
Все устаревшие javax.*
API JavaEE очищаются JakartaEE и снова выпускаются как jakarta.*
API с надлежащими метаданными maven.
Комментарии:
1. Спасибо, ошибки исчезли, но теперь я вижу, что он анализирует все поля, кроме одного, отмеченного знаком
@XmlPath
(ониnull
или0
). Вероятно, Eclipse Moxy все еще не работает.