Исключение приведения класса при попытке демаршалировать xml?

Попытка обойти исключение приведения класса здесь:

FooClass fooClass = (FooClass ) unmarshaller.unmarshal(inputStream);

выдает это исключение:

java.lang.ClassCastException: javax.xml.bind.JAXBElement

Я не понимаю этого - поскольку класс был сгенерирован инструментом xjc.bat - и классы, которые он сгенерировал, я вообще не менял - поэтому здесь не должно быть проблем с приведением - демаршаллер действительно должен возвращать мне класс который МОЖЕТ быть приведен к FooClass.

Есть идеи относительно того, что я делаю неправильно?


person Vidar    schedule 01.04.2009    source источник


Ответы (14)


Есть ли у FooClass аннотация XmlRootElement? Если нет, попробуйте:

Source source = new StreamSource(inputStream);
JAXBElement<FooClass> root = unmarshaller.unmarshal(source, FooClass.class);
FooClass foo = root.getValue();

Это основано на неофициальном руководстве по JAXB..

person Jon Skeet    schedule 01.04.2009
comment
Почему компилятор JAXB не помещает аннотацию XmlRootElement в мой класс в первую очередь - поскольку я не могу ее найти. Ваш код работает, но я хотел бы узнать больше, т.е. почему он работает? - person Vidar; 02.04.2009
comment
Пройдено - я изучил только достаточно далеко, чтобы решить исходную проблему :) Я действительно мало знаю о JAXB ... - person Jon Skeet; 02.04.2009
comment
кажется, что немаршал принимает только один аргумент. это не работает для меня - person maoanz; 22.02.2013
comment
@maoanz: Он перегружен. См. jaxb.java.net/nonav /2.2.6/docs/api/javax/xml/bind/ - person Jon Skeet; 22.02.2013
comment
@JonSkeet: но нет unmarshal, который принимает аргумент InputStream и Class. - person splash; 01.07.2013
comment
в моем случае это был вариант этого ответа: я скопировал FooClass и забыл изменить @XmlRootElement (foo) в новом классе: / - person user1075613; 05.11.2018

Используйте 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?

person Rahul Thakur    schedule 21.05.2012
comment
И что мне делать с этим schemaObject? - person Line; 31.05.2017
comment
Прошло много времени, но если я правильно помню, объект здесь представляет ваш POJO, вместо этого используйте свой класс и демаршалируйте его до его экземпляра. Затем вы можете использовать его, как хотите, в своем приложении. - person Rahul Thakur; 02.06.2017
comment
Обратитесь к: stackoverflow.com/questions/10243679/ - person Rahul Thakur; 02.06.2017

Сегодня я столкнулся с той же проблемой, увидел здесь ответы, провел небольшое исследование и решил, что наиболее универсальным решением является использование JAXBIntrospector. Следовательно -

FooClass fooClass = (FooClass ) unmarshaller.unmarshal(inputStream);

следует записать как

FooClass fooClass = (FooClass) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));

Или даже лучше, чтобы сделать его более общим -

T t = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));
person Gaurav B    schedule 10.01.2015

Для более полного объяснения прочтите эта статья. Оказывается, ваш XSD должен быть правильно настроен, т.е. должен быть какой-то корневой элемент, охватывающий все остальные элементы.

XJC действительно пытается добавить аннотацию @XmlRootElement к классу, который мы генерируем из сложного типа. Точное условие несколько уродливо, но основная идея заключается в том, что если мы можем статически гарантировать, что сложный тип не будет использоваться несколькими разными именами тегов, мы помещаем @XmlRootElement.

person Vidar    schedule 29.04.2009

Мы потратили слишком много часов на возня с фабричным классом JAXB, чтобы удовлетворить демаршаллера. Мы узнали, что использование демаршаллера без вызова фабрики объектов, созданной 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);
    }
person MAbraham1    schedule 11.02.2011

Я бы посмотрел на XML-файл и убедился, что это примерно то, что вы ожидаете увидеть.

Я бы также временно изменил код на:

Object o = unmarshaller.unmarshal(inputStream);
System.out.println(o.getClass());

Если первый из них не работает, то приведение класса происходит внутри метода демаршалирования, в случае успеха вы можете увидеть фактический класс, который вы возвращаете, а затем выяснить, почему это не то, что вы ожидаете.

person TofuBeer    schedule 01.04.2009

Основываясь на предварительных ответах коллег, на всякий случай, если кто-то все еще ищет ответ.

У меня возникла проблема с тем, что корневой элемент моей схемы определялся как:

<schema>
  <element name="foo" type="bar" />
  <complexType name="bar" />
</schema>

И поэтому я получал исключение Cast Exception по адресу:

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());

Это решило проблему для меня.

person Alberto A. Medina    schedule 02.11.2011

Вы абсолютно уверены, что FooClass является корневым элементом входного источника xml, который вы ему передали? Unmarshall вернет объект корневого элемента, созданного xjc.

person Greg Noe    schedule 01.04.2009

Иногда у вас есть определение XSD с несколькими различными корневыми элементами (например, XSD, определенный в WSDL), и в этом случае в сгенерированных классах отсутствует @XmlRootElement. Итак, как уже писал пользователь mbrauh, вам нужно получить значение JAXBElement. В моем случае я использовал:

FooClass request = ((JAXBElement< FooClass >) marshaller.unmarshal(new StreamSource(classPathResource.getInputStream()))).getValue();

Таким образом, используя дженерики, вы легко можете избежать двойного приведения типов.

person Marek Branicky    schedule 03.08.2014

Если у вас есть доступ, и вы можете изменить 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 сгенерирует корневой элемент!

person Antho    schedule 13.11.2018

Укажите @XmlRootElement (name = "defineName", namespace = "namespace") для объекта преобразования.

person user752749    schedule 09.09.2011

Я также столкнулся с ошибкой «Javax.xml.bind.JAXBElement не может быть преобразован в» и нашел это очень простое решение:

FooClass fooClass = (FooClass) ((JAXBElement) u.unmarshal(new File("xml/foo.xml")) ).getValue();

Поскольку, по-видимому, возвращается объект типа JAXBElement, вам нужно вместо этого привести его значение.

Источник: https://forums.oracle.com/thread/1625944

person mbrauh    schedule 30.10.2013

Попробуй это:

JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement element = (JAXBElement) unmarshaller.unmarshal( new StringReader(xmlString));
Foo foo = (Foo)element;
person LazyCoder    schedule 15.07.2016

В моем случае я получаю сообщение об ошибке при попытке отправить петицию мыла из приложения SOAPUI. Мне нужно установить для свойства «убрать пробелы» значение true, чтобы пропустить эту ошибку.

При отладке полученного содержимого отображается список следующего содержания:

[0] = "\n"
[1] = JAXBElement
[2] = "\n"

Надеюсь помочь кому-нибудь.

person Iván Minguet García    schedule 06.11.2018