I have to marshall a fragment of my root xml object :
Header header = ebicsNoPubKeyDigestsRequest.getHeader();
JAXBElement<org.ebics.h003.EbicsNoPubKeyDigestsRequest.Header> jaxbElement =
new JAXBElement<EbicsNoPubKeyDigestsRequest.Header>(
new QName("header"), EbicsNoPubKeyDigestsRequest.Header.class, header);
byte[] headerXml = JAXBHelper.marshall(jaxbElement, true);
but when I marshall ebicsNoPubKeyDigestsRequest the namespaces are not the same (in header fragment I have : xmlns:ns4="http://www.ebics.org/H003" but in ebicsNoPubKeyDigestsRequest I have xmlns="http://www.ebics.org/H003")
If I marshall the header object directly, without using JAXBElement, I have an No @XmlRootElement error
How I can have the same namespaces?
NB : I already use a NamespacePrefixMapper class :
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
if (namespaceUri.equals("http://www.ebics.org/H003")) {
return "";
} else if (namespaceUri.equals("http://www.w3.org/2000/09/xmldsig#")) {
return "ds";
} else if (namespaceUri.equals("http://www.ebics.org/S001")) {
return "ns1";
} else if (namespaceUri.equals("http://www.w3.org/2001/XMLSchema-instance")) {
return "ns2";
}
return "";
}
});
EDIT : here the different package-info.java :
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.ebics.org/H003", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.ebics.h003;
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.ebics.org/S001", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.ebics.s001;
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.w3.org/2000/09/xmldsig#", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.w3._2000._09.xmldsig_;
Without seeing your actual XML schema, files and JAXB generated classes (and their annotations) I can only advise you to try an adapt the following example to your scenario.
Given that you have a JAXB generated class like the following:
which is in the package
testand there is apackage-info.javafile in it like this:the following code:
will print this:
You can probably probably omit a the
NamespacePrefixMapperimplementation entirely.Play with omitting particular
namespaceelements from any of the annotations and see how the output changes.Blaise Doughan (a Java XML binding expert, probably lurking around somewhere near) has posted some info regarding this issue on his blog, see his post for some more insight.
Based on the input provided by Baptiste in chat I propose the following solution (I think this is the most painless).
Compile your schema files with XJC normally (
$ xjc .). This will generatepackage-java.infofiles for each of the generated packages. I assume this schema isn’t updated everyday, so you’re safe to make modifications on thepackage-info.javafiles (even though there will be some line comments in those files telling you not to do it—do it anyway). If the schema gets updated and you have to re-compile it run XJC with the-npaswitch, which tells it not to generate thosepackage-info.javafiles automatically, so (ideally) you can’t overwrite your hand-crafted files (if you use version control you can/should include these (handmade) files in the repository).Based on the provided schema files four packages are generated, so I’ll include my version of the modified
package-info.javafiles.After this you create your
JAXBContextlike this:(I’ve noticed that you don’t use actually use the
h000package so I’ve omitted it from the package name list. If it is included, then the marshalled XML’s root tag will probably contain its namespace and prefix mapping, even tough it isn’t used.)After this, you unmarshall your input XML and do whatever you want to with the object in memory.
Now, if you want to marshall only the
headertag which is nested inside theebicsNoPubKeyDigestsRequestyou have to wrap it inside aJAXBElement<...>because theheader‘s typeEbicsNoPubKeyDigestsRequest.Headerisn’t annotated with the@XmlRootElementannotation. You have two (in this case one) way to create this element.Create an
ObjectFactoryinstance for the corresponding package and use itsJAXBElement<T> createT(T t)function. Which wraps its input into aJAXBElement<...>. Unfortunately however, for theheaderfield’s type (given your schema files) XJC generates no such method, so you have to do it by hand.Basically you’ve almost done it right, but when creating the
JAXBElement<...>instead of passing itnew QName("header")you have to create a fully-qualifed name, which implies that the namespace is specified too. Passing only the name of the XML tag isn’t sufficient, because JAXB won’t know this way that this particularheadertag is part of the"http://www.ebics.org/H003"namespace. So do it like this:I didn’t test if changing only the
QNameinstantiation solves your problem, but maybe it will. However I think it won’t and you have to manually manage your prefixes to get a nice and consistent result.