What is the Jaxb equivalent of a Text node value? - java

I am looking to convert a class that looks like this ...
public class Amenity {
public String id;
public String value;
}
into the following XML using JaxB annotations:
<amenity id="id-string-here">value-string-here</amenity>
Does anyone know what annotation to use on the value member variable to accomplish this? The closest I've gotten so far is:
#XmlRootElement
public class Amenity {
#XmlAttribute
public String id;
#XmlElement
public String value;
}
Unfortunately this approach doesn't allow me to specify that the value member variable should not be rendered as its own tag <value></value>.

I'm not 100% sure about this, but try to use an #XmlValue annotation instead of #XmlElement.

It looks like the question was referring to text nodes not CDATA nodes, but here is a link on how EclipseLink JAXB (MOXy) handles CDATA:
http://bdoughan.blogspot.com/2010/07/cdata-cdata-run-run-data-run.html

This documentation writes:
Q. How can I cause the Marshaller to generate CDATA blocks?
A. This functionality is not available from JAXB directly, but you can configure an Apache Xerces-J XMLSerializer to produce CDATA blocks. Please review the JaxbCDATASample.java sample app for more detail.
(btw, this does not answer your particular question, but since the question title is misleading, and this is the first google result for jaxb CDATA, I'm answering a bit different question)

JAXB does not support marshaling/marshaling to/from CDATA xml types.

Related

Java spring. Annotations for tricky serialization to json and xml

I'm trying to rewrite some API serialization from custom mappers to annotation-based style and faced with one hard mapping (which was earlier custom-serialized to json and xml separately) that I can not "translate" to. (Serialization is made with Jackson.)
In the POJO we have a collection, e.g.
class Data {
Set<Integer> tags;
}
which should be serialized in xml like:
<tags>
<tag id="1"/>
<tag id="2"/>
</tags>
and in json like:
{
"tags":[1,2]
}
Strait method with
#XmlElementWrapper(name="tags")
#XmlElement(name="tag")
gives good json, but incorrect xml like
<root>
<tags>
<tag>1<tag/>
<tag>2<tag/>
</tags>
</root>
cause there is no attribute specification.
I tried to wrap a bit with:
class Data{
#XmlElementWrapper(name="tags")
#XmlElement(name="tag")
Set<Tag> tags;
}
class Tag{
#XmlAttribute(name="id")
Integer id;
}
But this produces unwanted key in json format, like:
"tags":[
{"tag":{"id":1}},
{"tag":{"id":2}}
]
Ok, then. I tried to specify custom json serializer(implementing JsonSerializer and injecting with #JsonSerialize(using = ...) ), but seems it also affects xml "render".
Is it possible to do the trick with annotations only? Or mb is it possible somehow use default json serialization and custom xml serializtaion for some class? .e.g.
use custom xml serialization only for Reasons class in such way
class Data {
#XmlElement("tags")
Reasons tags;
}
but let all surrounding data be "render" with general strategy.
Simply create a getter annotated with #JsonValue will tell Jackson to produce a single value, without any field name.
This mapping:
#XmlRootElement
public class Data{
public Set<Tag> tags;
}
public class Tag{
#XmlAttribute
public Integer id;
#JsonValue
public Integer getId() {
return id;
}
}
Will then produce:
{"tags":[2,1]}
And:
<data><tags id="2"/><tags id="1"/></data>
PS: You're using JAXB annotations, i don't think Jackson will honor them.
To get the XML result above, you need to use JAXB:
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(Data.class, Tag.class);
Marshaller m = context.createMarshaller();
m.marshal(value, writer);
System.out.println(writer.getBuffer().toString());
As a final note, i'm not super fan of using a single mapping for multiple representations. It's probably good for simple stuff, but if your code grows more complex than this, i strongly suggest you create two sets of classes (one for XML mapping and one for JSON), maybe with a common interface.

Marshal an object as one of its properties with Jackson (as for value objects i.e primitive types wrappers)

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

Marshalling nested objects with JAXB - unwrapped

I've got a very simple problem here, but after using Google for over an hour now, I still cannot find a good solution and it starts to cost too much money..
In my app I use REST as an API, basically only with JSON as payload type, and Enunciate for documentation of the API. As you might know, enunciate will generate an xsd schema from the classes. I am therefore in the situation, that I need to configure all the DTO's for Jackson/JSON handling with the suitable annotations, and also with JAXB annotation to ensure the generated schema is correct and can be parsed with XJC into the correct classes!
Although that is not very difficult to achieve and works flawless in most of the cases, I have a simple but somehow special case, in which it completely fails.
Assuming the following classes:
#JsonRootName(value = "location")
public class Location {
private String label;
#JsonUnwrapped
private Address address;
// constructors, getters, setters ommited..
}
//// new file
public class Address{
private String city;
private String street;
private String postCode;
}
This works 100% with Jackson/JSON. The embedded Address object will be unwrapped so that the JSON looks like this:
{
"label":"blah",
"street":"Exchange Road",
"city":"Stacktown"
"postCode":"1337"
}
This works forth and back with Jackson.
JAXB on the other hand is able to parse (most of) the Jackson annotations, so that generally you wont have problems with using simple objects in both worlds. #JsonUnwrapped though sadly is NOT supported by JAXB, and strangely that (from my POV) quite simple usecase seems to be not reflectable with any JAXB annotation at all.
What happens is, that the generated schema contains the embedded Address object, without any attributes/elements. Therefore the class generated by XJC will contain that Address object reference. And this ultimately leads to erroneous JSON from a app that will use the schema to generate objects...
Any ideas?
The JAXB (JSR-222) specification does not define an equivalent to Jackson's #JsonUnwrapped. For a long time we have offered that functionality in the EclipseLink MOXy implementation of JAXB via our #XmlPath extension.
#XmlPath(".")
private Address address;
For More Information
I have written more about MOXy's #XmlPath extension on my blog:
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html

How to ignore/disable/revert/override JAXB class-level #XmlJavaTypeAdapter in certain situations?

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?

XML mapping with #XmlAnyElement

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.

Categories