Исключение класса Cast при попытке демонтировать xml? - PullRequest
48 голосов
/ 01 апреля 2009

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

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

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

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

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

Есть идеи, что я делаю не так?

Ответы [ 14 ]

105 голосов
/ 02 апреля 2009

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

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

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

16 голосов
/ 21 мая 2012

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

15 голосов
/ 10 января 2015

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

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

должно быть записано как

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

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

T t = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));
9 голосов
/ 29 апреля 2009

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

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

3 голосов
/ 11 февраля 2011

Мы потратили слишком много времени, суетясь с заводским классом 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);
    }
3 голосов
/ 02 апреля 2009

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

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

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

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

2 голосов
/ 02 ноября 2011

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

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

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

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

1 голос
/ 03 августа 2014

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

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

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

1 голос
/ 02 апреля 2009

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

0 голосов
/ 13 ноября 2018

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

...