2009-04-01 3 views
39

Пытаясь пройти в классе литого исключения здесь:Исключение класса Cast при попытке unmarshall xml?

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

бросает это исключение:

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

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

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

ответ

93

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

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

Это основано на Unofficial JAXB Guide.

+2

Почему имеет JAXB компилятор не помещает аннотацию XmlRootElement в мой класс в первую очередь т - так как я не могу найти его. Ваш код работает, но я хотел бы узнать больше - например, почему он работает? – Vidar

+0

Pass - я только исследовал достаточно далеко, чтобы решить оригинальную проблему :) Я не очень много знаю о JAXB ... –

+0

Ярмарка - но спасибо за то, что помогли мне в любом случае. – Vidar

1

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

3

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

Я также временно изменить код на:

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

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

9

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

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

+0

Эта ссылка, на которую вы указываете, является лучшим ответом –

3

Мы потратили слишком много часов на ловкость с фабричным классом 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); 
    } 
0

Specify @XmlRootElement (имя = "specifyName", пространство имен = "пространство имен") для преобразования объекта.

2

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

я вопрос, имеющий корневой элемент моей схемы определяется как:

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

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

12

Использование JAXBIntrospector на JAXBElement, чтобы получить SchemaObject как >>

JAXBContext jaxbContext = JAXBContext.newInstance(Class.forName(className)); 
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
Object schemaObject = JAXBIntrospector.getValue(unmarshaller.unmarshal(new ByteArrayInputStream(xmlString.getBytes()))); 

См: when does JAXB unmarshaller.unmarshal returns a JAXBElement<MySchemaObject> or a MySchemaObject?

+3

Это решение просто прост и отлично подходит для литья – maoanz

+0

Спасибо. Это также общее решение. –

+1

А потом, что я должен делать с этим объектом schemaObject? – Line

0

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

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

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

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

1

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

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

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

11

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

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

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

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

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

T t = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream)); 
0

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

JAXBContext jc = JAXBContext.newInstance(Foo.class); 
Unmarshaller unmarshaller = jc.createUnmarshaller(); 
JAXBElement element = (JAXBElement) unmarshaller.unmarshal(new StringReader(xmlString)); 
Foo foo = (Foo)element; 
Смежные вопросы