Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB is confused about root elements?

Tags:

java

jaxb

visio

I'm trying to marshal a file using the Visio XML Schema, which consists of 3 schema files and produces three packages when java source is generated with XJC:

  • com.microsoft.schemas.visio._2003.core
  • com.microsoft.schemas.visio._2006.extension
  • com.microsoft.schemas.office.visio._2010.extension

The root element is VisioDocument, and all of the classes I'm using are in the 2003 package.

Here is my approach to marshalling my XML file:

VisioDocumentType visioDoc = new VisioDocumentType();
... manipulated here ...
JAXBContext jc = JAXBContext.newInstance("com.microsoft.schemas.visio._2003.core");
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(new JAXBElement<VisioDocumentType>(new QName("uri","local"), VisioDocumentType.class, visioDoc), bw);

When executed, I receive this error:

javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: unable to marshal type "com.microsoft.schemas.visio._2003.core.PagePropsType" as an element because it is missing an @XmlRootElement annotation]

I am using PagePropsType, but it is not a root element. Why does JAXB think it is?

like image 516
Chris Avatar asked Oct 24 '22 15:10

Chris


2 Answers

The problem resides in the ... manipulated here ... part of your code.

Based on the assumption that you do the following (or something similar).

// you create a page prop
PagePropsType pageProps = ...

// then you feed it to a shape sheet
ShapeSheetType shapeSheet = ...
shapeSheet.getTextOrXFormOrLine().add(pageProps);

(ShapeSheetType is a superclass for StyleSheetType, et cetera.)

If this's the case, then your problem lies in adding the pageProps to the list directly.

If you take a look at the getTextOrXFormOrLine() method's documentation it lists what kind of types the list can hold. Every type is wrapped in a JAXBElement<...> so you have to wrap pageProps before adding it to the list.

You should do it like this:

ObjectFactory objectFactory = new ObjectFactory();
JAXBElement<PagePropsType> pagePropsElement = objectFactory.createShapeSheetTypePageProps(pageProps);

(Note that I've used XJC 2.2.4 to compile the schemas; for me every class' name is suffixed with Type. Maybe this is why I ended up with VisioDocumentType instead of VisioDocument like you, but it shouldn't matter.)

like image 179
Kohányi Róbert Avatar answered Nov 15 '22 10:11

Kohányi Róbert


If you check your generated code, you will find a ObjectFactory class in there. This class should have a method that returns a VisioDocument wrapped in a JAXBElement, and that it the object that you want to pass to the marshaller.

Same applicable to all objects you set inside VisioDocument - don't create them with 'new' but use ObjectFactory.

like image 35
maximdim Avatar answered Nov 15 '22 08:11

maximdim