Исключение приведения класса при попытке отменить сопоставление xml?
Вопрос
Пытаюсь обойти исключение приведения класса здесь:
FooClass fooClass = (FooClass ) unmarshaller.unmarshal(inputStream);
выдает это исключение:
java.lang.ClassCastException: javax.xml.bind.JAXBElement
Я этого не понимаю - поскольку класс был сгенерирован инструментом xjc.bat - и классы, которые он сгенерировал, я вообще не изменял - так что здесь не должно быть проблем с приведением - unmarshaller действительно должен возвращать мне класс, который МОЖНО привести к FooClass .
Есть какие-нибудь идеи относительно того, что я делаю не так?
Решение
Делает 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<MySchemaObject> или MySchemaObject?
Сегодня я столкнулся с такой же проблемой, увидел ответы здесь, провел некоторое исследование и, на мой взгляд, наиболее общим решением является использование Джаксбинтроспектор.Следовательно -
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
.
Я бы посмотрел на XML-файл и убедился, что это примерно то, что вы ожидаете увидеть.
Я бы также временно изменил код на:
Object o = unmarshaller.unmarshal(inputStream);
System.out.println(o.getClass());
Если первый из них завершается неудачей, то приведение класса происходит внутри метода unmarshal, если это удается, то вы можете увидеть фактический класс, который вы получаете обратно, а затем выяснить, почему он не такой, каким вы ожидаете его видеть.
Мы потратили слишком много часов, возясь с заводским классом 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);
}
Основываясь на предварительных ответах коллег, на случай, если кто-то все еще ищет ответ.
У меня была проблема с тем, что корневой элемент моей схемы определялся как:
<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());
Это решило проблему для меня.
Вы абсолютно уверены, что FooClass является корневым элементом источника ввода xml, который вы ему передали?Unmarshall вернет объект корневого элемента, созданного xjc.
Иногда у вас есть определение XSD с несколькими различными корневыми элементами (например, XSD, определенный в WSDL), и в этом случае в сгенерированных классах отсутствует @XmlRootElement.Итак, как уже писал пользователь mbrauh, вы должны получить значение JAXBElement.В моем случае я использовал:
FooClass request = ((JAXBElement< FooClass >) marshaller.unmarshal(new StreamSource(classPathResource.getInputStream()))).getValue();
Таким образом, используя дженерики, вы можете легко избежать двойного приведения типов.
Укажите @XmlRootElement(имя="specifyName", пространство имен="namespace") для преобразующего объекта.
Я также столкнулся с ошибкой "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;
В моем случае я получаю ошибку при попытке отправить soap-петицию из приложения SOAPUI.Мне нужно установить свойству 'strip whitespaces' значение true, чтобы пропустить эту ошибку.
При отладке полученного содержимого отображается список со следующим содержимым:
[0] = "\n"
[1] = JAXBElement
[2] = "\n"
Надеюсь, помочь кому-нибудь.
Если у вас есть доступ и вы можете изменить XSD.Для меня эта проблема возникает, когда я генерирую XSD из XML с помощью IDEA.
С помощью этого xml :
<?xml version="1.0"?>
<schema>
<element name="foo" type="bar" />
<complexType name="bar" />
</schema>
ИДЕЯ сгенерируйте подобный 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 таким образом (измените свой корневой элемент "schema", чтобы получить 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 сгенерирует корневой элемент !