I would like to achieve something like this.
<zoo>
<lion> ... </lion>
<dog> ... </dog>
</zoo>
I have this class here.
public class MainGroup {
private List<Widget> widgets;
#XmlAnyElement
public List<Widget> getWidgets() {
return widgets;
}
public void setWidgets(List<Widget> widgets) {
this.widgets = widgets;
}
}
And this Widget superclass has got subclasses such as Button, Combobox...
I would like to achieve something like this.
<MainGroup>
<Button>...</Button>
<Combo>...</Combo>
</MainGroup>
I am having this exception
[com.sun.istack.internal.SAXException2: class com.test.Button nor any of its super
class is known to this context.
I tried adding #XmlElementRef but it is still not working.
#XmlElementRefs({
#XmlElementRef(name="Button", type=Button.class),
#XmlElementRef(name="Combo", type=Combo.class)
})
Mapping your Use Case
My answer is based on information gathered from one of your related questions:
Why doesn't JAXB writes out SWT Widgets?
Since you are mapping classes for which you do not have the source (and therefore can't add JAXB annotations), I would recommend using the #XmlElements mapping.
#XmlElements({
#XmlElement(name="Button", type=Button.class),
#XmlElement(name="Combo", type=Combo.class)
})
public List<Widget> getWidgets() {
return widgets;
}
#XmlElements corresponds to the XML Schema concept of xsd:choice.
http://blog.bdoughan.com/2010/10/jaxb-and-xsd-choice-xmlelements.html
About #XmlRootElement
Ok, I am missing quite a lot of things out here. It seems like I add
to add this #XmlRootElement annotation to my subclasses of Button and
Combo to achieve that.
Can anyone explain to me why I need that annotation in my
subclasses... I am confused, I thought an XML would only have a
#XmlRootElement which in my case should be in MainGroup class.
#XmlRootElement corresponds to global elements in the XML schema, which involves more that just the root element in the document you are unmarshalling. I'll describe a couple of the roles below:
#XmlElementRef
#XmlElementRef corresponds to the concept of substitution groups. In an XML Schema you can specify that one global element is substitutable for another. In JAXB #XmlRootElement (and #XmlElementDecl) is leveraged to specify global elements:
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
#XmlAnyElement
#XmlAnyElement corresponds to the concept of xs:any in XML Schena. This is part of the document that is pretty free form. In JAXB when you map a property with #XmlAnyElement(lax=true) it will convert elements matching #XmlRootElement declarations into the corresponding domain objects.
http://blog.bdoughan.com/2010/08/using-xmlanyelement-to-build-generic.html
Ok, I am missing quite a lot of things out here.
It seems like I add to add this #XmlRootElement annotation to my subclasses of Button and Combo to achieve that.
Can anyone explain to me why I need that annotation in my subclasses... I am confused, I thought an XML would only have a #XmlRootElement which in my case should be in MainGroup class.
Related
EDIT: Previous answer does not work (it stills create a nested object)
I'm using Jersey and Jackson.
I got a class like
#XmlAccessorType(XmlAccessType.NONE)
public class Name {
private String value;
#XmlValue
public String getValue(){...}
public void setValue(String value){...}
}
used as in
public class Person{
#XmlElement(name = "IDName")
public Name getName(){...}
}
I'd like to marshal Name object as the value of it's identity property.
How can I achieve that?
<Person>
<IDName>foo</IDName>
</Person>
instead of
<Person>
<IDName>
<Value>foo</Value>
</IDName>
</Person>
I'd tried both to indicate in Person that Name object should be marshalled as itself.getValue() and either to indicate within Name class to marshal without any element wrapper (its fields directly) with no luck.
A possible solution is replacing #XmlValue annotation with Jackson's #JsonValue to make it work (tested).
I infer from http://wiki.fasterxml.com/JacksonJAXBAnnotations that it can be the only solution for now
According to this the official documentation
#javax.xml.bind.annotation.XmlValue
The field/property to which this annotation is applied will be named "value".
So maybe it's limited by design. Any better answer, specially if using JAXB annotations alone, will be much appreciated
Our model classes are annotated with #XmlJavaTypeAdapter (at the class-level). Unmarshalling works fine for the root element and containment/nesting (according to what we implemented in our custom XmlAdapter).
So far, we were happy campers for both XML and JSON serialization/deserialization. However, a new need arose and I can't figure out how to implement it ?
In certain situations, I'd like to be able to "revert" to default JAXB behavior for containment: I want the class-level #XmlJavaTypeAdapter annotation to be ignored/overriden.
I spent hours reading Blaise Doughan's blog (http://blog.bdoughan.com/) and searching StackOverflow and Google but can't find an elegant/pragmatic solution.
Here is a quick setup to illustrate what we currently have (please note that all our JPA/Hibernate/other annotations are not listed for simplicity-sake but they do exist in our model classes (POJOs)):
Class Master
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
#XmlJavaTypeAdapter(XmlMasterAdapter.class)
public class Master {
#XmlElement
private Long masterPrimaryKey;
#XmlElement
private String name;
}
Class Detail
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
#XmlJavaTypeAdapter(XmlDetailAdapter.class)
public class Detail {
#XmlElement
private Long detailPrimaryKey;
#XmlElement
private Master master; // reference/foreign key. No need for #XmlJavaTypeAdapter since it's defined at the class-level in Master.
#XmlElement
private String value;
}
When Master is used as a the root element, the XML is like this:
<master>
<masterPrimaryKey>1234</masterPrimaryKey>
<name>master name</name>
</master>
When Master is used as a contained/nested element, the XML is like this: (thanks to our custom XmlAdapter, the <master> element is "summarized" by its primary key)
<detail>
<detailPrimaryKey>5678</detailPrimaryKey>
<master>1234</master>
<value>detail value</value>
</detail>
So far, everything works fine and we're happy with it.
Now, our new need:
I'd like containment to work in a different way in specific situations.
I want the class-level #XmlJavaTypeAdapter on Master to "temporarily" be ignored/reverted/overridden in a specific context. I'd expect the default JAXB unmarshaller to kick-in (as if there had never been a class-level #XmlJavaTypeAdapter on the contained classes).
Think about a data-import situation where we receive the master and all the details in one payload. As if they were all independent root elements wrapped in a big DTO/transport container.
Here is the XML presenting what we want:
<masterDetailImport>
<master>
<!-- Primary keys omitted because of the import mode -->
<name>master name</name>
</master>
<details>
<detail>
<value>detail 1 value</value>
</detail>
<detail>
<value>detail 2 value</value>
</detail>
<detail>
<value>detail 3 value</value>
</detail>
</details>
</masterDetailImport>
Class MasterDetailImport
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class MasterDetailImport implements Serializable
{
#XmlElement
#PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT
private Master master;
#XmlElementWrapper(name="details")
#XmlElement
#PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT
private List<Detail> detail = new ArrayList<Detail>();
}
What I'm looking for is the magic [yet non-existing] #PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT annotation that would allow me to instruct JAXB to do as if #XmlJavaTypeAdapter had never been defined at the class-level for the nested classes.
So far, the solutions we envisioned [and don't like] are:
Create "mirror" DTO objects for deserialization only when we must support import. The are many cons with this approach (duplicate code only used for deserialization, adapters to copy the DTO content into the model class, more unit tests to write/maintain, etc).
Get rid of class-level #XmlJavaTypeAdapter on all our entities we want to be able to import/nest and explicitly use #XmlJavaTypeAdapter on all attributes where nesting/containment is used. I tested this approach and know it would work. However, I think it's error prone and not as elegant as defining it at class-level and be able to have an exception/special-case/override handling telling JAXB to temporarily behave as if it never knew #XmlJavaTypeAdapter has been defined on the class.
I'm running out of ideas here... I tried looking for JAXB's default XML adapter but was not successful: javax.xml.bind.annotation.adapters.XmlAdapter<ValueType,BoundType> is abstract and inherits from Java.lang.Object.
Now, the simple question:
How to implement #PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT ?
Thanks in advance !
An XmlAdapter in JAXB will always be applied, but you can put logic in the XmlAdapter itself to handle your use case. By default a new instance of XmlAdapter will be created each time it will be used, if your XmlAdapter is stateful you can set an instance on the Marshaller or Unmarshaller so that it will be used instead. You can leverage this to help determine if it should be applied or not.
Below is a link to an answer I gave to a related question where a stateful XmlAdapter is used to inline an object the first time it is reference, and then marshal it as a link each subsequent time it is referenced.
Can JAXB marshal by containment at first then marshal by #XmlIDREF for subsequent references?
I'm trying to use an XmlAdapter to unmarshal XML into a custom collection type (that intentionally does not implement the Collection interface due to a conflicting restriction imposed by another use of the class, which unfortunately fails if the class contains any collections). The difficulty is that the XML nodes that will be placed into the collection are not wrapped in a wrapper element.
Here's what my XML essentially looks like:
<xml>
<foo></foo>
<bar>1</bar>
<bar>2</bar>
</xml>
I can make JAXB unmarshall this to the following POJO:
class Naive {
Foo foo;
List<Bar> bar;
}
However, what I want to do is the following:
class Bars {
// There will be a fixed number of these, known in advance
Bar bar1;
Bar bar2;
}
class BarsAdapter extends XmlAdapter<ArrayList<Bar>, Bars> {
...
}
class Custom {
Foo foo;
#XmlJavaTypeAdapter(BarsAdapter.class) // won't work
Bars bar;
}
As you can see, I wrote an XmlAdapter that wants to adapt the entire list, not the individual elements, but it never gets invoked for unmarshalling. (It does get invoked for marshalling.)
If my XML contained a wrapper around the <bar> elements, then I know how to solve this:
<xml>
<foo></foo>
<wrapper>
<bar>1</bar>
<bar>2</bar>
</wrapper>
</xml>
because then I could annotate the bars field with #XmlElement(id="wrapper") and the adapter would get correctly called. However, the XML schema comes from an RFC and is entirely unchangeable, so I am stuck as to how to proceed. Any ideas appreciated!
I have an XML document that looks something like the following:
Note that I cannot change the schema because it is part of a standard XML Schema (Library of Congress METS).
<amdSec ID="AMDSEC001">
<digiprovMD ID="DMD001">
<mdWrap MDTYPE="OBJECT">
<xmlData>
<object xsi:type="file">
.....
</object>
</xmlData>
</mdWrap>
</digiprovMD>
<digiprovMD ID="DMD001_EVENT">
<mdWrap MDTYPE="EVENT">
<xmlData>
<event xsi:type="event">
.....
</event>
</xmlData>
</mdWrap>
</digiprovMD>
</amdSec>
As you can see, the inner element <mdWrap> can contain elements of different types; in this case they're <event> and <object>, but it isn't constrained to just those two types. Creating two classes (like below), marshals okay, but this doesn't work for unmarshalling.
class ObjectMDWrap {
#XmlElementWrapper(name = "xmlData")
#XmlElement(name = "object")
List<MyObject> object; //Wrapped in list to use #XmlElementWrapper
}
class EventMDWrap {
#XmlElementWrapper(name = "xmlData")
#XmlElement(name = "event")
List<MyEvent> event; //Wrapped in list to use #XmlElementWrapper
}
What can I do so that JAXB unmarshals the correct "type" of MDWrap?
I think, the best solution in this case is a generating POJO classes using XJC tool.
Download XSD file which describe XML file.
Using XJC tool convert XSD file into POJO classes. If XSD is not correct - fix it.
Make some changes if you need in generated classes.
Use this classes in marshalling / unmarshalling process.
I was able to figure out the solution, and it's much simpler than I initially thought (which speaks to my relative inexperience with XML and JAXB). By creating my MDWrap class in the following way
class MDWrap {
#XmlAnyElement(lax = true)
#XmlElementWrapper(name = "xmlData")
Object wrappedMD;
}
Then MDWrap can contain an object of any type, and will unmarshal properly, as long as the class of which wrappedMD is an instance of is annotated with #XmlRootElement. The trick is to annotate wrappedMD as XmlAnyElement.
If I have a class (A) that contains several properties of the same type (interface B).
I've used the suggestion in http://jaxb.java.net/guide/Mapping_interfaces.html to use a combination of #XmlRootElement and #XmlAnyElement to get around the interface problem:
public interface B {...}
public class A {
...
#XmlAnyElement
public B getFirstB(){...}
#XmlAnyElement
public B getSecondB(){...}
}
// some concrete implementations of B
#XmlRootElement
public class BImpl implements B {...}
#XmlRootElement
public class AnotherBImpl implements B {...}
I get the following:
<a>
<bImpl/>
<anotherBImpl/>
</a>
But I want to distinguish between the properties. How do I get:
<a>
<firstB>
<bImpl/>
</firstB>
<secondB>
<anotherBImpl/>
</secondB>
</a>
As the properties are not collections, I can't use #XmlElementWrapper.
I don't really want to change the code if avoidable.
Any thoughts appreciated. Marshalling in JAXB seems to be very tricky.
Replace #XmlAnyElement with #XmlElement(type = Object.class). This will distinguish individual fields.
More details on this solution in my answer to a related question.
You cannot marshal interfaces in JAXB. How would the unmarshaller know how to instantiate your interface?
Check this out, it has a really nice explanation.
I think, no magic can happen in your case. Either use a simple wrapper class (for classic JAXB) or use #XmlPath (for MOXy) (acknowledgements to Blaise Doughan).