Исключение класса Cast при попытке демонтировать xml?
Попытка обойти исключение приведения класса здесь:
FooClass fooClass = (FooClass ) unmarshaller.unmarshal(inputStream);
выдает это исключение:
java.lang.ClassCastException: javax.xml.bind.JAXBElement
Я не понимаю этого - поскольку класс был сгенерирован инструментом xjc.bat - и сгенерированные им классы я не изменил вообще - поэтому здесь не должно быть проблем с приведением типов - демон-маршаллер должен действительно возвращать мне класс это МОЖЕТ быть приведено к FooClass.
Есть идеи, что я делаю не так?
14 ответов
Есть ли FooClass
иметь XmlRootElement
аннотаций? Если нет, попробуйте:
Source source = new StreamSource(inputStream);
JAXBElement<FooClass> root = unmarshaller.unmarshal(source, FooClass.class);
FooClass foo = root.getValue();
Это основано на неофициальном руководстве JAXB.
Используйте JAXBIntrospector на JAXBElement, чтобы получить schemaObject как >>
JAXBContext jaxbContext = JAXBContext.newInstance(Class.forName(className));
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object schemaObject = JAXBIntrospector.getValue(unmarshaller.unmarshal(new ByteArrayInputStream(xmlString.getBytes())));
Обратитесь: когда JAXB unmarshaller.unmarshal возвращает JAXBElement
Я столкнулся с той же проблемой сегодня, увидел ответы здесь, провел некоторые исследования и считает, что наиболее общим решением является использование JAXBIntrospector. Отсюда -
FooClass fooClass = (FooClass ) unmarshaller.unmarshal(inputStream);
должно быть написано как
FooClass fooClass = (FooClass) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));
Или даже лучше, чтобы сделать его более общим -
T t = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));
Для более полного объяснения прочитайте эту статью. Оказывается, ваш XSD должен быть правильно настроен, то есть должен быть какой-то корневой элемент, охватывающий все остальные элементы.
XJC пытается поставить
@XmlRootElement
аннотация для класса, который мы генерируем из сложного типа. Точное условие несколько уродливо, но основная идея состоит в том, что если мы можем статически гарантировать, что сложный тип не будет использоваться несколькими разными именами тегов, мы добавим@XmlRootElement
,
Мы потратили слишком много времени, чтобы поиграть с фабричным классом JAXB, чтобы удовлетворить потребности маршаллера. Мы узнали, что использование unmarshaller без вызова сгенерированной JAXB фабрики объектов работает нормально. Надеюсь, что пример кода погасит чье-то разочарование:
System.out.println("Processing generic-type unmarshaller: ");
MessageClass mcObject = unmarshalXml(MessageClass.class, msgQryStreamSource,
NAMESPACE + "." + "MessageClass");
public static <T> T unmarshalXml(Class<T> clazz, StreamSource queryResults,
String contextNamespace)
{
T resultObject = null;
try {
//Create instance of the JAXBContext from the class-name
JAXBContext jc;
jc = JAXBContext.newInstance(Class.forName(clazz.getName()));
Unmarshaller u = jc.createUnmarshaller();
resultObject = clazz.cast(u.unmarshal(queryResults));
}
//Put your own error-handling here.
catch(JAXBException e)
{
e.printStackTrace();
}
catch (ClassCastException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return clazz.cast(resultObject);
}
Я бы посмотрел на файл XML и убедился, что это примерно то, что вы ожидаете увидеть.
Я также временно изменил бы код на:
Object o = unmarshaller.unmarshal(inputStream);
System.out.println(o.getClass());
Если первый отказывает, то приведение класса происходит внутри метода unmarshal, если он успешен, вы можете увидеть реальный класс, который вы получаете, а затем выяснить, почему это не то, что вы ожидаете.
Опираясь на предварительный просмотр ответов от коллег, на всякий случай кто-нибудь еще ищет ответ.
У меня была проблема с определением корневого элемента моей схемы как:
<schema>
<element name="foo" type="bar" />
<complexType name="bar" />
</schema>
И поэтому я получаю исключение броска на:
try {
javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(mobilityConfigType.getClass().getPackage().getName());
javax.xml.bind.Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
File f = FileUtil.toFile(this.getPrimaryFile());
mobilityConfigType = (MobilityModelConfigType)unmarshaller.unmarshal(FileUtil.toFile(this.getPrimaryFile()));
} catch (javax.xml.bind.JAXBException ex) {
java.util.logging.Logger.getLogger("global").log(java.util.logging.Level.SEVERE, null, ex); //NOI18N
}
Что я сделал, так это изменил первую строку блока try на:
javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(mobilityConfigType.getClass().getName());
Это решило проблему для меня.
Иногда у вас есть определение XSD с несколькими различными корневыми элементами (например, XSD, определенное в WSDL), и в этом случае в сгенерированных классах отсутствует @XmlRootElement. Так как пользователь mbrauh уже написал, вы должны получить значение JAXBElement. В моем случае я использовал:
FooClass request = ((JAXBElement< FooClass >) marshaller.unmarshal(new StreamSource(classPathResource.getInputStream()))).getValue();
Таким образом, используя дженерики, вы можете легко избежать двойного приведения типов.
Если у вас есть доступ, и вы можете изменить XSD. Для меня эта проблема возникает, когда я генерирую XSD из XML с IDEA.
С этим XML:
<?xml version="1.0"?>
<schema>
<element name="foo" type="bar" />
<complexType name="bar" />
</schema>
IDEA генерирует XSD подобным образом, и JAXB не будет генерировать корневой элемент:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="schema" type="schemaType"/>
<xs:complexType name="schemaType">
<xs:sequence>
<xs:element type="elementType" name="element"/>
<xs:element type="complexTypeType" name="complexType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="elementType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="name"/>
<xs:attribute type="xs:string" name="type"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="complexTypeType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="name"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
НО, если вы измените XSD таким образом (измените корневой элемент "схема", чтобы получить xs:complexType внутри тега xs: element):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="schema">
<xs:complexType>
<xs:sequence>
<xs:element type="elementType" name="element"/>
<xs:element type="complexTypeType" name="complexType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="schemaType">
<xs:sequence>
<xs:element type="elementType" name="element"/>
<xs:element type="complexTypeType" name="complexType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="elementType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="name"/>
<xs:attribute type="xs:string" name="type"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="complexTypeType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="name"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
JAXB сгенерирует корневой элемент!
Вы абсолютно уверены, что FooClass является корневым элементом входного источника xml, который вы передали? Unmarshall вернет объект корневого элемента, созданного xjc.
Укажите @XmlRootElement(name="defineName", namespace="namespace") для объекта преобразования.
В моем случае я получаю сообщение об ошибке при попытке отправить мыльную петицию из приложения SOAPUI. Мне нужно установить свойство 'strip whitespaces' в true, чтобы пропустить эту ошибку.
При отладке полученного контента, создается список со следующим контентом:
[0] = "\n"
[1] = JAXBElement
[2] = "\n"
Надеюсь помочь кому-нибудь.
Я также столкнулся с ошибкой "Javax.xml.bind.JAXBElement не может быть приведен к" и нашел это очень простое решение:
FooClass fooClass = (FooClass) ((JAXBElement) u.unmarshal(new File("xml/foo.xml")) ).getValue();
Поскольку, по-видимому, возвращается объект типа JAXBElement, вам нужно вместо этого типизировать его значение.
Источник: https://forums.oracle.com/thread/1625944
Попробуй это:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement element = (JAXBElement) unmarshaller.unmarshal( new StringReader(xmlString));
Foo foo = (Foo)element;