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

StackOverflow https://stackoverflow.com/questions/707084

  •  22-08-2019
  •  | 
  •  

Вопрос

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

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 сгенерирует корневой элемент !

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top