users@jaxb.java.net

Re: Custom mapping for Maps in JAXB

From: Leo Romanoff <romixlev_at_yahoo.com>
Date: Mon, 21 Jun 2010 16:10:45 -0700 (PDT)

Hi Wolfgang,

Having implemented this solution for the Map<String, String> case, I'm
asking myself now, if it is possible to do a similar thing for Map<String,
JAXB-annotated-class>. So, basically, if values related to keys are actually
complex objects of annotated types that can be handled by JAXB, is it
possible to tell JAXB to marshall/unmarshall these sub-elements?

Or is it like this: Once you have an xsd:anyType element, everything inside
this element, including any JAXB-aware subelements, cannot be parsed by JAXB
and is represented also as a DOM element?

Thanks,
  Leo


Leo Romanoff wrote:
>
> Hi,
>
> Here is the most convenient and pretty simple solution for the problem
> I've implemented so far based on Wolfgang's proposals:
>
> In your JAXB-annotated class you put the following annotations for your
> map field:
>
> @XmlRootElement(name="YourClassElementName")
> class YourClass {
> ...
>
> @XmlElement(name="YourMapElementName")
> // Here is the trick: Use use special map adapter for maps (see below)
> @XmlJavaTypeAdapter(JsonMapAdapter.class)
> private Map<String,String> yourMap = new LinkedHashMap<String,String>();
>
> ...
> }
>
> and the JsonMapAdapter class can be defined somewhere like this:
>
> package your.jaxb.adapters;
>
> import java.util.LinkedHashMap;
> import java.util.Map;
>
> import javax.xml.bind.annotation.adapters.XmlAdapter;
>
> import javax.xml.parsers.DocumentBuilder;
> import javax.xml.parsers.DocumentBuilderFactory;
>
> import org.w3c.dom.Document;
> import org.w3c.dom.Element;
> import org.w3c.dom.Node;
> import org.w3c.dom.NodeList;
> import org.w3c.dom.Text;
>
> public class JsonMapAdapter extends XmlAdapter<Object, Map<?, ?>> {
>
> @Override
> public Map<?, ?> unmarshal(Object domTree) {
> Map<Object, Object> map = new LinkedHashMap<Object, Object>();
> Element content = (Element) domTree;
> NodeList childNodes = content.getChildNodes();
> if (childNodes.getLength() > 0) {
> for (int i = 0; i < childNodes.getLength(); i++) {
> Node child = childNodes.item(i);
> String key = child.getNodeName();
> // Skip text nodes
> if (key.startsWith("#"))
> continue;
> String value = ((Text) child.getChildNodes().item(0))
> .getWholeText();
> map.put(key, value);
>
> }
> }
> return map;
> }
>
> @Override
> public Object marshal(Map<?, ?> map) {
> try {
> DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
> DocumentBuilder db = dbf.newDocumentBuilder();
> Document doc = db.newDocument();
> Element customXml = doc.createElement("Map");
> for (Map.Entry<?, ?> entry : map.entrySet()) {
> Element keyValuePair = doc.createElement(entry.getKey()
> .toString());
> keyValuePair.appendChild(doc.createTextNode(entry.getValue()
> .toString()));
> customXml.appendChild(keyValuePair);
> }
> return customXml;
> } catch (Exception e) {
> e.printStackTrace();
> }
>
> return null;
> }
> }
>
> With this approach you only need one additional JAXB-annotation to achieve
> the required affect:
> @XmlJavaTypeAdapter(JsonMapAdapter.class)
>
> Best,
> Leo
>
>

-- 
View this message in context: http://old.nabble.com/Custom-mapping-for-Maps-in-JAXB-tp28779221p28953069.html
Sent from the java.net - jaxb users mailing list archive at Nabble.com.