JAXB marshalling: change element which should declare a namespace - java

When using JAXB marshalling, do I have an influence on which element a namespace/namespace prefix will be declared?
Currently, all namespace prefixes are declared at the root element, but due to strange limitations of the system which processes my XML I need to declare them at child elements (which would still result in a valid xml document).
A similar, but not identical request has been made to the official jaxb issue tracker and declined by a developer back in 2006. I'd like to know if this situation changed in the meanwhile or if some workarounds exist.
Any help is appreciated.
Example:
JAXB marshalling creates the following XML:
<outer xmlns:ns1="http://mydomain">
<inner>
<ns1:data/>
</inner>
</outer>
While I need to have something like
(ns1 prefix is not declared at the root element):
<outer>
<inner xmlns:ns1="http://mydomain">
<ns1:data/>
</inner>
</outer>

JAXB (JSR-222) does not provide a means to control where namespace declarations occur. JAXB providers tend to put the namespaces on the root element (for performance reasons), but they are not required to.
Below is a link to an answer I gave to a similar question where XMLStreamWriter is extended to control when the namespace declarations get reported.
JAXB marshalling XMPP stanzas

Related

How to use XSD for non namespaced documents

Recently I've encountered a service that returns its results in XML, in sort of following fashion
<event>
<event-header>
...
</event-header>
<event-body>
...
</event-body>
</event>
Notice that the document does not have a namespace definition. As a result, there is no "official" schema that I can use.
I have written a schema definition that I can use to generate classes that are usable in code to interact with equivalent elements in the document. From observation I can tell that the document format does not change (field order remains the same, fields are not introduced or go away). But question stands, can I still deserialize the provided document using my schema? As far as I know, schemas must define a namespace, and in theory the documents above and below
<event xmlns="http://saltyjuice.lt/dragas/event-service/1.0/event-schema.xsd">
<event-header>
...
</event-header>
<event-body>
...
</event-body>
</event>
are not equivalent.
For reference, I'm using stax and woodstox 6 as implementation.
You can have a schema for a no-namespace document, I don't know why you thought otherwise. It's not ideal, because a namespace can guide people to the right schema. But it's allowed. Anyway, even with a namespace, it's quite possible to have several schemas for the same namespace (usually, versions and variants).

How to prevent JAXB from writing unused namespaces during marshalling

Has someone ever been able to remove unused namespaces during marshal of an object using JAXB? Here is a link of the requested feature: https://github.com/javaee/jaxb-v2/issues/103 (see description)
Is there a property for configuring JAXB for this?
Has this been fixed in MOXy?
I am currently traversing the object that needs to be marshalled and extract all classes that need to be bound into Class[] classesToBeBound.
Then I create a new JAXBContext.newInstance(classesToBeBound)
The unused namespaces now are not included in the XML.
I know that xml validation is valid even with the unused namespaces but to me this is something a framework should handle.
The following link https://blogs.oracle.com/enterprisetechtips/entry/customizing_jaxb mentions various fixed (see middle of the text somewhere) but when trying to find the solution in those links either the link is broken or no-one really solved it.
Any comments are welcome.
(EDIT)
Plain text:
GIVEN
a new instance of JAXBContext and add 2 classes with each a separate namespace.
WHEN
marshalling a class that has these 2 classes as a property but only 1 of them is not null
THEN
I expect only the namespace of the property that is not null to be visible in the XML.
BUT the ACTUAL is
that both namespaces are in the xml.
So my question was how can I remove or tell JAXB to NOT write the unused namespaces?
To put it in java-code:
GIVEN
public class Foo{
private Bar bar; //namespace something2
private User user; //namespace user
}
WHEN
JAXBContext c = JAXBContext.newInstance(Foo.class, Bar.class, User.class);
...
Foo foo = new Foo();
foo.setBar(null);
foo.setUser(new User("Bob"));
marshaller.umarshal(foo);
THEN I expect the xml to be
<foo xmlns="something1" xmlns:user="user">
<user:name>Bob</user:name>
</foo>
BUT the ACTUAL is (note the something2 namespace)
<foo xmlns="something1" xmlns:user="user" xmlns:bar="something2">
<user:name>Bob</user:name>
</foo>
Of course this is a simplified example and our specification of a type has around 30 different namespaces.
As far as I know, this is indeed not possible in JAXB - and is actually a well-known issue. As you have noticed it, the list of produced namespaces are the ones that have been registered in your JAXBContext, and not the ones that are effectively used when marshalling :-(
I the past, I used the same workaround as you (identify the various used classes and narrow the JAXBContext to this limited set of classes).
Another typical workaround is a 2-step processing: a first marshalling with JAXB, followed by a XSLT transformation to get rid of let's says "polluting" namespaces.
This may not be possible as while marshaling of this objects hierarchy happen, at the time of creating root tag, information about which objects are null v/s not null may not be available. Any attempt to get this information in advance may also have side-effects associated with it as respective accessor methods are invoked. Hence JAXB will statically use info from JAXBContext to have this information populated.
You can try using a different javax.xml.bind.Marshaller implementation.
For example org.eclipse.persistence.jaxb.JAXBMarshaller implementation deals well with this case and remove all unnecessary namespaces when marshall the object.
To do so you need to do the next steps:
Add eclipselink-2.6.5.jar to the classpath in order to use the org.eclipse.persistence.jaxb.JAXBMarshaller. If you're using gradle you can add compile 'org.eclipse.persistence:eclipselink:2.6.5' to your dependencies.
Create a jaxb.properties file in the same package where you've the objects to marshall (following the example in your question - JAXBContext c = JAXBContext.newInstance(Foo.class, Bar.class, User.class);, in the package of one of these classes Foo, Bar or User).
In the jaxb.properties file, add the follow property which specify the desired Context factory:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Doing this, the org.eclipse.persistence.jaxb.JAXBMarshaller will be used as a javax.xml.bind.Marshaller implementation on Runtime. And then no unnecessary namespaces will appear when you marshall the objects.
I tried the solution albciff suggested in this thread and it turns out that Eclipse Moxy handles this much better than the reference implementation (org.glassfish.jaxb).
Here's info on how to switch to the Moxy implemenation of JAXB:
https://wiki.eclipse.org/EclipseLink/Examples/MOXy/JAXB/SpecifyRuntime
The documentation doesn't specify it but you can also change the jaxb implemenation with just a single configuration file instead of a jaxb.properties in each package where your jaxb annotated classes exists. Just create a file META-INF/services/javax.xml.bind.JAXBContext (yep unconventional filename) with the contents:
org.eclipse.persistence.jaxb.JAXBContextFactory
This makes the jaxb ContextFinder use the Eclipse Moxy implementation for all jaxb marshalling in the jvm.
Another option is to use a system property -Djavax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Disclaimer though: The namespaces declaration aren't minimized/optimized for the current payload, but at least it doesn't include ALL namespaces that are part of the jaxb grammar. The integration I'm working on went from a staggering 700+ declared namespaces (about 60KB worth of useless overhead per sent message) to at best 3 declarations in a message. Though for messages which have a lot of different types in them, all of the namespaces which are valid in that particular message is declared. That means in some case I still get ~30 declared namespaces when only one would suffice for the current payload.
I guess that SOAP isn't the way to go if you need to optimize on bandwidth.
Yes, they could be omitted. I'm not sure I understood the problem you face correctly. But there is no problem to marshal an object without namespaces.
Try something like this marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "class for which namepsace not needed"); in your case it should be
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, bar.class);

How to tell XStream to ignore child elements that have the 'class' attribute

I have some persisted XML that was generated by XStream, and looks like:
<CalculationDefinition>
<id>47</id>
<version>3</version>
<name>RHO error (pts)</name>
<expression class="com.us.provider.expression.AbsoluteValue">
....
</expression>
</CalculationDefinition>
I want to persist this content differently now, and want to tell XStream to simply ignore the expression element entirely. There's many links around that talk about how to do this with a MapperWrapper (eg XStream JIRA) but as far I can tell it doesn't work for an element that has a 'class' attribute.
This can be worked around by leaving an 'expression' field in the CalculationDefinition, but I'd rather not have to keep it there now that it's not used in code.
You could filter the incoming XML using XSL and removing the expression nodes, before passing it to XStream.

Mapping Java with JAXB annotations to XSD keys/keyrefs

We are using JAXB to map Java classes into XML files. Currently we use the Java-to-XSD approach by annotating the Java classes.
This works fine in general but we've hit the following problem now: we want an attribute of one XML element to refer to another XML element by it's name/ID. Imagine some XML describing a conceptual schema, with the entities defined in <entity> elements and <property> elements used to establish the links. The #type attribute of the properties should then reference an entity in the same file.
Is it possible to model this using JAXB? What I imagine is having xsd:key and xsd:keyref elements in the schema which should then be resolved to the matching Java objects when unmarshalling.
It's non-trivial, but possible:
http://weblogs.java.net/blog/2005/08/15/pluggable-ididref-handling-jaxb-20

Duplicate namespace declarations in JAXB generated XML

I am using JAXB to generate XML from Java objects, it's a realtime, quite high message rate application and works fine most of the time. However occassionally and without any obvious clues as to why, I am getting duplicate namespace declarations in the generated XML. eg:
<UpdateRequest xmlns="http://xml.mycomp.com/ns/myservice"
xmlns="http://xml.mycomp.com/ns/myservice">
<field1>value</field1>
...
</UpdateRequest>
Has anyone seen this behaviour before?
Check if the xsd code of this class allow the creation of more than 1 instance of the repeated attribute. if so, you can avoid this repetitions setting the number of instances of the xmlns attribute for each UpdateRequest object.
If the problem is your code (maybe there is being created this attribute twice) and you have limited the number of instances of the attribute (as i said above), the program will show an error at runtime complaining that you are trying to insert an attribute already defined.
A solution might be available at this link.
here's the relevant section quoted verbatim from the above link that may be relevant for you:
Similar explicit inclusion of a schema
type in an instance document's element
occurs if you instantiate a JAXB
element using an object of some
(abstract) XML schema base type so
that the element would have the
element tag of the base type.
Second, avoid xs:anySimpleType since
this will also create multiple
references to the namespaces bound to
xsi and xs, and type attributes
containing the actual type. And you
lose JAXB's advantage of having typed
fields in your Java classes so that
you lose all the checks the Java
compiler might do, and for
unmarshalling you'll have to handle
all the conversions yourself.

Categories