How to prevent JAXB from writing unused namespaces during marshalling
Asked Answered
A

6

26

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.

Absinthe answered 8/4, 2014 at 15:28 Comment(1)
I am not sure if i understand your issue correctly. Do you want to remove all null valued attributes from the resulting xml? And isnt this a duplicate of #11215985Output
G
4

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.

Gorlovka answered 20/6, 2018 at 19:29 Comment(0)
L
1

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.

Limitation answered 14/7, 2014 at 21:54 Comment(0)
D
1

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.

Downfall answered 26/5, 2020 at 8:37 Comment(0)
E
0

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.

Eternity answered 25/7, 2019 at 12:29 Comment(0)
D
-1

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.

Dhammapada answered 8/4, 2014 at 15:38 Comment(2)
Updated the initial question with more info. Can you specify HOW I can omit the unused namespaces? Whether or not it makes sense to remove them is another debate as I do know that it is syntactically correct that they are in the XML ;-)Absinthe
Can you post the annotations you have on Foo, Bar and User classes? BTW, you mean marshalling not unmarshalling, right?Dhammapada
B
-2

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

Belletrist answered 26/6, 2018 at 6:53 Comment(1)
jaxb version 2.2*Belletrist

© 2022 - 2024 — McMap. All rights reserved.