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.
Related
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);
I have read a similar topic on the matter:
getting the minOccurs attribute using XSOM from an element
but the answer seemed a bit suboptimal, especially when there are hundreds of elements in one xsd file. Is it really the only way to do this, or is there a simpler way?
I would like to retrieve it from XSElementDecl if it's at all possible.
You can't. It's not a property of the element declaration, it's a property of the element particle, which is the relationship between an element declaration and the content model in which it is used.
Now, if the element declaration is a local declaration then it's true enough it can only be used in one content model, so the declaration and the particle are one-to-one, and in the SCM defined in XSD 1.1 it seems that if {variety} is local then you can get {parent} to find the containing model group, and then go back over the particles of this model group. But XSOM doesn't seem to reflect the {parent} property, which is not surprising, because it's not there in XSD 1.0, and there doesn't seem to be anything corresponding to the {scope} property either.
So, the API doesn't seem to allow navigation from the Element declaration to the particles that use that declaration. But then, how did you find the Element declaration if it wasn't via the particle?
I have to unmarshal a xml-soap string to a Java object using JAXB. The XML contains a lot of empty tags with filled attributes, for instance most information in the message is relayed as follows:
<ID code="123" codeSystem="12.12.12"/>
I am interested in the attributes.
Problem:
If I inspect the object after the unmarshalling, all the empty tags (like the one above) have no representation (e.g. are null) in the Java object. Only the filled tags (e.g. 123 have been added to the Java object.
Maybe this behaviour is conform xml standards, but I am still interested in the attributes.
Can someone tell me if there is a way to get the attributes??
Possible workaround: to give each element a default value ("") when its null by binding it to an adapter using the bindings-file. But I only succeeded in doing this for simple-types.
Used versions: we are using the jaxb implementation in Java 1.6
Many thanks.
Wybrand.
As there is no default value for XML attributes I would implement the initialization code in the afterUnmarshal method. There you could check all attributes you are interested in and set them to a valid non-null value.
For details how to use afterUnmarshal see: How can I have JAXB call a method after it has completed unmarshalling an XML file into an object?
I solved the problem. But the problem was not JAXB.
The party which sends the xml which I have to umarshall puts a 'null namespace' in the element declaration.
Xml fragment:
The id element has in its declaration xmlns="". (I presume this is a bug) and the root tag has the declaration xmlns:ns3="urn:hl7-org:v3"
For this reason (I think) the jaxb unmarshaller does not see the id element as part of the message.
Until now, I've been handling extensions by defining a placeholder element that has "name" and "value" attributes as shown in the below example
<root>
<typed-content>
...
</typed-content>
<extension name="var1" value="val1"/>
<extension name="var2" value="val2"/>
....
</root>
I am now planning to switch to using xsd:any. I'd appreciate if you can help me choose th best approach
What is the value add of xsd:any over my previous approach if I specify processContents="strict"
Can a EAI/ESB tool/library execute XPATH expressions against the arbitrary elements I return
I see various binding tools treating this separately while generating the binding code. Is this this the same case if I include a namespace="http://mynamespace" and provide the schema for the "http://mynamespace" during code gen time?
Is this WS-I compliant?
Are there any gotchas that I am missing?
Thank you
Using <xsd:any processContents="strict"> gives people the ability to add extensions to their XML instance documents without changing the original schema. This is the critical benefit it gives you.
Yes. tools than manipulate the instances don't care what the schema looks like, it's the instance documents they look at. To them, it doesn't really matter if you use <xsd:any> or not.
Binding tools generally don't handle <xsd:any> very elegantly. This is understandable, since they have no information about what it could contain, so they'll usually give you an untyped placeholder. It's up the the application code to handle that at runtime. JAXB is particular (the RI, at least) makes a bit of a fist of it, but it's workable.
Yes. It's perfectly good XML Schema practice, and all valid XML Schema are supported by WS-I
<xsd:any> makes life a bit harder on the programmer, due to the untyped nature of the bindings, but if you need to support arbitrary extension points, this is the way to do it. However, if your extensions are well-defined, and do not change, then it may not be worth the irritation factor.
Regarding point 3
Binding tools generally don't handle
very elegantly. This is
understandable, since they have no
information about what it could
contain, so they'll usually give you
an untyped placeholder. It's up the
the application code to handle that at
runtime. JAXB is particular (the RI,
at least) makes a bit of a fist of it,
but it's workable.
This corresponds to the #XmlAnyElement annotation in JAXB. The behaviour is as follows:
#XmlAnyElement - Keep All as DOM Nodes
If you annotate a property with this annotation the corresponding portion of the XML document will be kept as DOM nodes.
#XMLAnyElement(lax=true) - Convert Known Elements to Domain Objects
By setting lax=true, if JAXB has a root type corresponding to that QName then it will convert that chunk to a domain object.
http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
Let's say I have a doc.xml and corresponding doc.xsd. I use xpath to retrieve some nodes, so I get a list of org.w3c.dom.Node. How can I get type of each node from schema, eg. xs:integer, xs:string etc ?
Some solution would be to parse schema with xpath query "//NodeName[#type]" using node.getNodeName() as NodeName, but that's not perfect. I can't be sure that schema is elegant - what if NodeName exists in many places in schema and has not been extracted as a separate type?
So generally I am looking for a reliable solution to get the node type for ANY valid xml & xsd.
You should consider using JAXB. It will create Java classes for you based on the schema type. Then your XML docs are read into those classes, which are typed according to how you defined your XSD. Therefore xsd:int maps to java int(or Integer wrapper class, I can't recall), etc.
Cast your DOM Elements to TypeInfo: from there, you can access the type information you're looking for.
Unfortunately types as defined in an XML Schema (XSD) or Document Type Definition (DTD) are not directly tied to XML document they validate. The elements and attributes in an XML document do not inherently have a type they are just text. Think of an XSD as a script that validates an XML document rather than a set of type annotations for elements and attributes.
The XML specification does not define types as you are thinking of them here. Even Document Type Definitions (DTD) which can be embedded inside XML documents more about the structure of the document not the type of the data contained in elements and attributes.
The type system described in XML Schema is an optional layer of validation that can be applied to XML documents. Since this validation optional the standard XML APIs do not provide a way to bind the validation rules in an XSD to the actual attributes and elements.
I think it would be possible for an XML API to provide a mechanism to bind an XSD to a specific XML document, but I am not aware of an XML parser that does this. One reason why this is not so easy is that the type system that is defined in XML Schema is much richer than is supported in most mainstream programming languages. In your example you may only be interested in xs:integer, xs:string and the like but in XML Schema you can create types that specify ranges, patterns and other things that are just not possible with data types in most programming languages. To represent this complex type system in Java or any programming language would have to be done through a fairly complex API. The the question becomes it is really worth it? I would say probably not.
As per David Ds answer, slightly cleaner, call getSchemaTypeInfo() on an element or attribute