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?
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.)
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.
Related
I need help to find the approach of how to create xml multiple times while I will be changing only two fields everytime and rest of the fields would be same as now. Please tell me the way to do it in java?
This is the sample xml below:
I would be changing the value of <Id> and <Originator>
<TransactionBlk>
<Id>NIK</Id>
<CorrelationId />
<Originator>NIK</Originator>
<Service>GetIns</Service>
<VersionNbr>1</VersionNbr>
<VersionNbrMin>0</VersionNbrMin>
<MsgNm>Req</MsgNm>
<MsgFormatCd>XML</MsgFormatCd>
</TransactionBlk>
You can crate one class contain all this parameter as class variable, create getter and setter method. Create object of class set value by using setter method.
You can use JAXB API's class to convert your java object into XML format.
The JAXBContext class provides the client's entry point to the JAXB API.
It provides an abstraction for managing the XML/Java binding information
necessary to implement the JAXB binding framework operations: unmarshal,
marshal and validate.
Here is Doc reference for convert your Java object into XML.
Here are tutorial for same Tutorial Link
Sample Code :
#XmlRootElement(name="TransactionBlk_REQ",namespace="http://TransactionBlk.com")
#XmlAccessorType(XmlAccessType.FIELD)
public class TransactionBlk
{
#XmlElement(name = "Id")
private String id;
#XmlElement(name = "Originator")
private String Originator;
//Your getter and setter method.
}
TransactionBlk bean = new TransactionBlk();
//Set your parameter value here
StringWriter responseWriter = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(TransactionBlk.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(bean, responseWriter);
String xmlStr = responseWriter!=null?responseWriter.toString():null;
You can use XSLT to transform XML.
If all you're doing is printing a "boilerplate" document with changes in those two values, a, you could use the DPH (Desperate Perl Hacker) approach: simply assemble it as text, pausing to print the values at the appropriate places. To be safe, you should pre-scan the values to make sure they don't contain the <, >, or & characters and escape those if you find them.
For something more complex, or if you want to start learning how to do it "properly", look at the standard XML APIs for Java: DOM (the Document Object Model, an in-memory tree model of a document), SAX (an event-stream view of a document), and JAXP (tools to take an XML document and parse it into DOM or SAX so you can read it, and to take DOM or SAX and write those out as XML syntax). JAXP also provides standard APIs for invoking XPath to search a document and XSLT to apply a stylesheet to a document, so taken together these cover a huge percentage of the basic operations on XML.
You might want to look at some tutorials on using Java to manipulate XML. I'm certainly biased, not least because they published one of my articles, but in my experience IBM's DeveloperWorks website (https://www.ibm.com/developerworks/xml/) has had better-than-average material for learning about XML and other standards.
I generated code using moxy for different xsd-Files:
http://www.forum-datenaustausch.ch/generalinvoiceresponse_400.xsd
and
http://www.forum-datenaustausch.ch/xmlstandards_generelle_rechnung_beispiele_antwort_4.3_20100901.zip
I generated jaxb-classes for both xsd (using moxy). Then i tried unmarshal xml-files (genrated by eclipse) with this code:
public void tempTest() throws JAXBException{
JAXBContext jC = JAXBContext.newInstance(<package for corresponding type>.ResponseType.class);
jC.createUnmarshaller().unmarshal(ResponseTest.class.getResourceAsStream("/responses/generalInvoiceResponse_400.xml"));
}
With xml-File of 4.3-type (2nd link) this works fine but with xml of 400-type (1st link) i get this error:
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element {http://www.forum-datenaustausch.ch/de}response was not found in the project]
It seems to be a problem with the name-space. The name space is different but i can not see a relevant difference in generated code or generated xml - the name space is consistent.
so what could cause this problem (where is the difference) and how to solve it?
small addition: i also tried to unmarshal xml marshaled with jaxb/moxy-code:
public void marshall() throws JAXBException, FileNotFoundException {
JAXBContext jC = JAXBContext.newInstance(ResponseType.class);
ObjectFactory of = new ObjectFactory();
jC.createMarshaller().marshal( of.createResponse(of.createResponseType()),new FileOutputStream("simpleresponse.xml"));
}
this creates an very simple xml:
<?xml version="1.0" encoding="UTF-8"?>
<response xmlns="http://www.forum-datenaustausch.ch/de"/>
unmarshaling this yields the same error.
When creating a JAXBContext based on a model generated from an XML Schema you should always use the the newInstance method that takes the package name. This will ensure that all the necessary bits are processed.
JAXBContext jC = JAXBContext.newInstance("ch.forum_datenaustausch.de");
When you use the JAXBContext.newInstance(Class...) method the JAXB implementation is assuming that you started from Jav classes. Since the role of ObjectFactory can be played by any class annotated with #XmlRegistry the ObjectFactory class generated from the XML schema will be automatically picked up. You could do the following, but I still recommend the above approach:
JAXBContext jC = JAXBContext.newInstance(ResponseType.class, ObjectFactory.class);
UPDATE
Thank you! but could you probably explain why it is working with one
xsd and not with the other?
The schema where it "works" may have a global element with an anonymous type which causes an #XmlRootElement annotation to be generated meaning the ObjectFactory is not required. The other may have a global element with a named complex type which causes an #XmlElementDecl annotation on an ObjectFactory class to be generated.
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html
I also got same error message over WebLogic 12 but problem was due to namespace prefix.
It got fixed after explicitly adding name space in #Xmlrootelement(name="namespace:root tag name")
Please shed some light on JAXBContext configutation.
Given:
customer library com.mycompany.user01234 with several
JAXB-annotated classes
all classes are simple POJOs located in the same package
classes are annotated by #XmlType
Customer marshals instance of com.mycompany.user01234.UserClass1.class to the server via web service endpoint. On the server side I do the following:
JAXBContext jbc = JAXBContext.newInstance("com.mycompany.user01234")
Unmarshaller um = jbc.createUnmarshaller();
JAXBElement<Object> element = um.unmarshal(source, Object.class);
Object customerInput = element.getValue();
And it works fine ONLY if I patch customer library with following package-info.java:
#XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED)
package com.mycompany.user01234;
To my shame I havent found any clear explanation of what this #XmlNsForm annotation is and how it affects unmarshalling process. This is the first question.
The second question is whether it is possible (in the given layout) to put that QUALIFIED value into some properties or defaults for JAXBContext or use other non-declarative means allowing to get rid of package-info.java.
Many thanks in advance!
It corresponds exactly to the elementFormDefault attribute of an <xs:schema> element (i.e., the top-level element of an XML Schema document). What it does (with that constant) is state that elements from the namespace defined by the schema should be rendered with a qualifier (i.e., as <foo:bar> instead of <bar>); the exact way that the namespace is declared will also vary between the two styles. In terms of the XML infoset, the two styles are completely equivalent; if namespaces are declared correctly in the XML, JAXB should be equally happy (I believe it should only use the value when serializing).
You might want to try making your JAXBContext by passing in the class that you are expecting so that you are a little less reliant on discovery code (assuming it's a FooBar class that's really being produced):
JAXBContext jbc = JAXBContext.newInstance(FooBar.class);
FooBar customerInput = (FooBar) jbc.createUnmarshaller().unmarshal(source);
(The above code is abstracted from things that I do in my code's test suite that definitely already work.)
It seems the standard approach for deserializing JAXB XML is to specify the package name when creating the context. Then, JAXB looks up the class based on the root element:
JAXBContext jc = JAXBContext.newInstance("com.foo");
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal(new StringReader("<?xml version="1.0" encoding="UTF-8" standalone="yes"?><MyJaxb>..."));
I'm looking for a more flexible approach where I don't have to specify the package name and could still deserialize any object. This would be as simple as JAXB storing the package in the XML, but I can't seem to find out how to do this. I can write the code to do it myself but that would be unpleasant. It would like JAXB to do it, if possible. BTW, I am not using schemas, just Annotations and marshal/unmarshal. Any ideas?
Actually you can not deserialize "any" object with pure JAXB. You have to specify either packages (where ObjectFactory.class will be sought) or list of classes like JAXBContext.newInstance(Class1.class, Class2.class, Class3.class); That's how jaxb works, it's a part of agreement.
If your tasks are wider that that, e.g. building java classes from arbitrary xml data structure - it's also possible, but you have to be a bit more concrete - what do you mean under "more flexible approach".
You should be able to add more than one package when you get the instance of the jaxbcontext object. You can add as many packages as you want like below.
JAXBContext jc = JAXBContext.newInstance("com.foo.package1:com.foo.package2" );
however, I am not sure how you are gonna use it if you deserialize it into an Object instance?
Are you not gonna use what you have just deserialized?
Also Unmarshaller is not a thread safe class if your application is a multithreaded one.
Do you always need an ObjectFactory class when using JAXB?
Without it I get this exception:
javax.xml.bind.JAXBException:
"com.a.b.c"
doesnt contain ObjectFactory.class or
jaxb.index
I gather the ObjectFactory can be overkill. But given this exception I'm guessing you need it.. but not sure why?
You get that exception when you use the JAXBContext.newInstance(String) factory method, where you pass in the package name as the argument. This does require the ObjectFactory to be there, otherwise, JAXB doesn't know which classes to process.
If you don't have an ObjectFactory, you need to JAXBContext.newInstance(Class...) instead, passing in the explicit list of annotated classes to add to the context.
Instead of the ObjectFactory you can include a jaxb.index file which is a text file that contains a new line seperated list of Java classes.
For an example of using a jaxb.index file see:
http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
I was using Spring and I just had to change
Jaxb2Marshaller mlr = new Jaxb2Marshaller();
mlr.setContextPaths("","");
to
Jaxb2Marshaller mlr = new Jaxb2Marshaller();
mlr.setPackagesToScan("","");