I am trying to switch from JAXB RI 2.2.7 to MOXy JAXB 2.5.2 implementation.
I notice the following difference in namespace and prefix in the generated XML output snippet:
JAXB RI:
<xbrli:xbrl xmlns:xbrli="http://www.xbrl.org/2003/instance" xmlns:bd-algemeen="http://www.nltaxonomie.nl/7.0/basis/bd/items/bd-algemeen" xmlns:iso4217="http://www.xbrl.org/2003/iso4217">
<bd-algemeen:OperatingSystem contextRef="cc_131">W</bd-algemeen:OperatingSystem>
<xbrli:unit id="uu_692">
<xbrli:measure>iso4217:EUR</xbrli:measure>
</xbrli:unit>
</xbrli:xbrl>
MOXy:
<xbrli:xbrl xmlns:xbrli="http://www.xbrl.org/2003/instance" xmlns:bd-algemeen="http://www.nltaxonomie.nl/7.0/basis/bd/items/bd-algemeen">
<bd-algemeen:OperatingSystem contextRef="cc_131">W</bd-algemeen:OperatingSystem>
<xbrli:unit id="uu_662">
<xbrli:measure xmlns:ns0="http://www.xbrl.org/2003/iso4217">ns0:EUR</xbrli:measure>
</xbrli:unit>
</xbrli:xbrl>
1) How do I configure MOXy to output the same as the RI? The MOXy output is valid but The XML (actually XBRL) document I create must have predefined prefixes.
2) I use a an instance of "com.sun.xml.bind.marshaller.NamespacePrefixMapper" to indicate the prefix that should be used. However MOXy doesn't call this in case of the iso4217 namespace, why (I debugged the MOXy namespace resolver but got a bit lost ;)?
BTW: the prefixMapper is used by Moxy for other namespaces (like the "xbrli"), but not for this iso4217, what is the difference?
I haved added "bd-algemeen", as the prefix mapper is called for the prefix "bd-algemeen". This mapping doesn't use QName as used by iso4217.
3) I tried the #XmlSchema annotation in the pacakage-info.java in the generated iso4217 pacakge, to define the prefix, but no luck, neither do I want to use this as it concerns generated code that is easily overwritten.
The domain object:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "divide", "measures" })
#XmlRootElement(name = "unit")
public class Unit {
protected Divide divide;
#XmlElement(name = "measure")
protected List<QName> measures;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "operatingSystem"})
public static class TaxDataBedrijf {
#XmlElement(name = "OperatingSystem", namespace = "http://www.nltaxonomie.nl/7.0/basis/bd/items/bd-algemeen")
protected Astring1ItemType operatingSystem;
The creation of the Unit instance:
final Unit item = new Unit();
item.getMeasures().add(new QName("http://www.xbrl.org/2003/iso4217", "EUR", "iso4217"));
taxData = new TaxDataBedrijf();
taxData.setOperatingSystem(createOperatingSystem(context, 'W'));
I thought it might be because of the QName usage, but this is also directly used in other places and is used correctly. For example, Moxy is able to generate this snippet:
<xbrli:xbrl xmlns:xbrli="http://www.xbrl.org/2003/instance" xmlns:bd-domains="http://www.nltaxonomie.nl/7.0/basis/bd/domains/bd-domains" xmlns:bd-axes="http://www.nltaxonomie.nl/7.0/domein/bd/axes/bd-axes">
<xbrli:scenario>
<xbrldi:explicitMember dimension="bd-axes:TimeDimension">bd-domains:Current</xbrldi:explicitMember>
</xbrli:scenario>
</xbrli:xbrl>
And the corresponding java binding:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "value" })
#XmlRootElement(name = "explicitMember")
public class ExplicitMember {
#XmlValue
protected QName value;
#XmlAttribute(name = "dimension")
protected QName dimension;
}
And it's creation:
final ExplicitMember item = new ExplicitMember();
item.setDimension(new QName("http://www.nltaxonomie.nl/7.0/domein/bd/axes/bd-axes", "TimeDimension"));
item.setValue(new QName("http://www.nltaxonomie.nl/7.0/basis/bd/domains/bd-domains", "Current"));
Please some advice on how to solve this such that I can use MOXy instead of the RI (where to look in the Moxy code maybe?).
The behaviour you are seeing is a bug, I have opened up the following issue for it:
https://bugs.eclipse.org/452713
I got it working with the correct namespace notation, that is, that it generates:
<xbrli:unit id="uu_382">
<xbrli:measure>iso4217:EUR</xbrli:measure>
</xbrli:unit>
I spend some (lot ;) time debugging the Moxy code and comparing the namespaces that were correctly used and discovered that the ObjectFactory for the above snippet doesn't contain any #XmlElementDecl annotation like the ones that were working. When adding this, it works, namely:
private static final QName EUR_QNAME = new QName("http://www.xbrl.org/2003/iso4217", "EUR", "iso4217");
#XmlElementDecl(namespace = "http://www.xbrl.org/2003/iso4217", name = "EUR", substitutionHeadNamespace = "http://www.xbrl.org/2003/instance", substitutionHeadName = "item")
public JAXBElement<EUR> createEURO() {
return new JAXBElement<EUR>(EUR_QNAME, EUR.class, null, createEUR());
}
I noticed that when the Xbrl (root tag) mapping is created, it will loop through the properties, and one of these properties is the property "itemsAndTuplesAndContexts". It then loop through the associated reference elements (Moxy code: MappingGenerator.generateMappingForReferenceProperty(..)) and will add them to it's namespace resolver map with generated prefix, that is stored in it's descriptor.
During marshalling, it will use the prefix mapper to map it's stored namespaces. Because I added #XmlElementDecl declaration for the iso4217 element, it's found a referencing Element, and as such it's added to the namepace resolver map of the Xbrl root element, and as such used during marshalling in the prefix mapper.
A few questions I don't have very clear:
Why is this #XmlElementDecl required in Moxy, and not by the JaxB RI?
Why wasn't this #XmlElementDecl elements generated during the code generation with XJC?
#Blaise: do you think it's a bug ?
property "itemsAndTuplesAndContexts" declaration:
#XmlElementRefs({ #XmlElementRef(name = "unit", namespace = "http://www.xbrl.org/2003/instance", type = Unit.class),
#XmlElementRef(name = "context", namespace = "http://www.xbrl.org/2003/instance", type = Context.class),
#XmlElementRef(name = "item", namespace = "http://www.xbrl.org/2003/instance", type = JAXBElement.class),
#XmlElementRef(name = "tuple", namespace = "http://www.xbrl.org/2003/instance", type = JAXBElement.class),
#XmlElementRef(name = "footnoteLink", namespace = "http://www.xbrl.org/2003/linkbase", type = JAXBElement.class) })
protected List<Object> itemsAndTuplesAndContexts;
Can we map XML like
<root>
<tagA>
<prop>111</prop>
<prop>222</prop>
<prop>333</prop>
<prop>444</prop>
</tagA>
<tagB>
<prop>555</prop>
<prop>666</prop>
</tagB>
<tagC>
<prop>777</prop>
</tagC>
</root>
to
class MyDto {
private List<TagA> tagAProps;
private List<TagB> tagBProps;
private List<TagC> tagCProps;
}
using JAXB? I am not sure how to use annotation to directly map elements to collection type. Straight mapping into POJO has five different classes (Root, TagA, TagB, TagC and Prop). Of which TagA, TagB and TagC being all similar. So I want to have this minimum number of class.
You can leverage the #XmlElementWrapper and #XmlElement annotations for this:
#XmlRootElement(name="root")
#XmlAccessorType(XmlAccessType.FIELD)
class MyDto {
#XmlElementWrapper(name="tagA")
#XmlElement(name="prop")
private List<String> tagAProps;
#XmlElementWrapper(name="tagB")
#XmlElement(name="prop")
private List<String> tagBProps;
#XmlElementWrapper(name="tagC")
#XmlElement(name="prop")
private List<String> tagCProps;
}
class foo
{
public static List parse(String input_xml)
{
try {
// JAXB context created.
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
ByteArrayInputStream input = new ByteArrayInputStream(input_xml.getBytes());
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
// Error comes while unmarshalling the input
Root root = (Root) jaxbUnmarshaller.unmarshal(input);
HashMap<String,String> map1 = new HashMap<String,String>();
//... Code to retrieve values from "root" and put it in list
}
}
public static void main(String[] args)
{
String input= "<?xml version=\"1.0\"?>"
+"<root>"
+"<attribs R:SSB:12 = \"ABC\"/>" +
"</root>";
List list = parse(input);
}
}
"attribs" can contains multiple "attributes-value" pairs, hence i need to "UNMARSHAL" it using Jaxb.
I tried using QName , but its throwing error.
Question : While parsing , I am getting this error : "An invalid second ':' was found in the element type or attribute name." .... But i couldn't find any help .... attribute name and values are dynamic in my case.
Thanks for any help!!!*/
The problem is that you are trying to feed JAXB with invalid XML:
<attribs R:SSB:12 = "ABC">
Colon symbol has special meaning in XML: it separates namespace and attribute (or tag) name under that namespace. That's why attribute (or tag) can only contain one colon.
If your attribute names are coming from elsewhere, you have to escape colons to make them valid XML attributes. Try replacing colons with dash symbol (-), for example:
<attribs R-SSB-12="ABC">
The extra : is causing problems as by default JAXB expects the portion behind the : is the namespace prefix. You can solve this by forcing JAXB to use a parser that is not namespace aware.
This can easily be done with a SAX parser and leveraging JAXB's UnmarshallerHandler as the ContentHandler.
Full Example
java xml annotation get field with namespace, <aaa:bbb>value</aaa:bbb>
Reflecting on JAXB annotated objects, is there a way to determine if a class/field/method will result in a xsi:type attributed during marshaling?
Is XmlElement annotation,
annotation.type != javax.xml.bind.annotation.XmlElement.DEFAULT.class
the only case I need to worry about?
I'm writing a Lua unmarshaler where we have dropped much of the usual xml type info and I'm trying to figure-out how to match the incoming Lua to JAXB.
Thanks.
--Update--
Here is simple example that shows the problem:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement()
#XmlSeeAlso({ Cat.class, Dog.class })
public class Animal {
#XmlElement()
public List<Animal> critters;
#XmlAttribute
public String type;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement()
public class Dog extends Animal {
public Dog() {
this.type = "German Shepherd";
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement()
public class Cat extends Animal {
public Cat() {
this.type = "Black";
}
}
When I receive an Animal object can I query critter's annotation to detect that it should be a Dog or Cat and not an Animal?
There are a couple circumstances where a JAXB (JSR-222) implementation will write out an xsi:type attribute.
If the field/property is of type Object (or is annotated with #XmlElement(type=Object.class)) and not mapped with #XmlAnyElement(lax=true) and holds an instance of an Object that the JAXBContext has mappings for.
The default mechanism for representing inheritance will result in an xsi:type attribute to represent subclasses (see: http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html).
in JAXB, if annotations were not provided, the element names will be derived from the property names not fields, but what about attributes in this case? is there any default behavior for writing out attributes back to the XML file?
1) If annotations were not provided:
Every public getter/setter pair and every public field will be
automatically bound to XML, unless annotated by {#link XmlTransient}
For example
public class Cat
{
public String name = "tomcat";
private String nick = "catalina";
public int getAge() { return 5; }
public void setAge(int age) {}
}
after
JAXB.marshal(cat, System.out);
output is
<cat>
<name>tomcat</name>
<age>5</age>
</cat>
2) What about XML attributes? XML attribute is named like field or getter/setter pair and placed in the root node
for example
#XmlAccessorType(XmlAccessType.FIELD)
public class Cat
{
String name = "tomcat";
#XmlAttribute
String nick = "catalina";
#XmlAttribute
String home = "java.home";
int age = 5;
}
output is
<cat home="java.home" nick="catalina">
<name>tomcat</name>
<age>5</age>
</cat>