Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize HashTable<String, String> to XML using JAXB?

I am trying to use JAXB to serialize a HashTable<String, String> to XML. I am very new to Java (came from C#), so I am kinda perplexed by this task.

I have seen the following code:

public static <T> String ObjectToXml(T object, Class<T> classType) throws JAXBException
{
  JAXBContext jaxbContext = JAXBContext.newInstance(classType);
  StringWriter writerTo = new StringWriter();
  Marshaller marshaller = jaxbContext.createMarshaller();
  marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
  marshaller.marshal(object, writerTo); //create xml string from the input object
  return writerTo.toString();
}

Which is invoked like so: ObjectToXml(o, ClassOfO.class), but HashTable<String, String>.class is wrong (that I already know).

Can Java gurus out there show me how to invoke this code? Proposing a simpler implementation (along with an invocation example, of course) is most welcome as well.

Thanks.

like image 214
mark Avatar asked Sep 23 '11 20:09

mark


4 Answers

You will need to create a wrapper class to hold onto the Hashtable:

package forum7534500;

import java.util.Hashtable;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Wrapper {

    private Hashtable<String, String> hashtable;

    public Hashtable<String, String> getHashtable() {
        return hashtable;
    }

    public void setHashtable(Hashtable<String, String> hashtable) {
        this.hashtable = hashtable;
    }

}

Then you can do the following:

package forum7534500;

import java.io.StringWriter;
import java.util.Hashtable;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Wrapper.class);
        Wrapper wrapper = new Wrapper();
        Hashtable<String, String> hashtable = new Hashtable<String,String>();
        hashtable.put("foo", "A");
        hashtable.put("bar", "B");
        wrapper.setHashtable(hashtable);
        System.out.println(objectToXml(jc, wrapper));
    }

    public static String objectToXml(JAXBContext jaxbContext, Object object) throws JAXBException
    {
      StringWriter writerTo = new StringWriter();
      Marshaller marshaller = jaxbContext.createMarshaller();
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
      marshaller.marshal(object, writerTo); //create xml string from the input object
      return writerTo.toString();
    }

}

This will produce the following output:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wrapper>
    <hashtable>
        <entry>
            <key>bar</key>
            <value>B</value>
        </entry>
        <entry>
            <key>foo</key>
            <value>A</value>
        </entry>
    </hashtable>
</wrapper>

Things to Note

  • JAXBContext is a thread-safe object and should be created once and reused.
  • Hashtable is synchronized, if you do not need this then using HashMap is the common replacement.
  • The convention is to start Java method names with a lower case letter.

Customizing the Mapping

You can use an XmlAdapter in JAXB to customize the mapping of any class. Below is an link to a post on my blog where I demonstrate how to do just that:

  • http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html
like image 90
bdoughan Avatar answered Nov 15 '22 09:11

bdoughan


Unfortunately, JAXB is not able to directly serialize a Map or HashMap instance directly. Instead, you'll have to do some sort of translation from a Map into a list of entries that have a key and a value. Try looking into this Stack Overflow question and see if it can help you. This problem shows up a lot in Google, and the sad answer is that JAXB doesn't know how to serialize a Map.

like image 26
fruchtose Avatar answered Nov 15 '22 10:11

fruchtose


Bah! If you had only googled on jaxb and hashmap you would have directly found this: http://download.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html

But, yes, I kind of agree that 'perplexion' is a good description of the feeling of the non-obviousness of the task.

like image 27
forty-two Avatar answered Nov 15 '22 10:11

forty-two


While you might be familiar with C# reified generics, Java's generics are for compile time only, they go away at runtime. That's why, at runtime, even if you have an instance with established generics (Such as String for HashTable) at runtime those generics go away, so all you can do is obtain the class of the thing (HashTable here) and not the actual generic types (String here). In short: compile time Hashtable<String,String> becomes HashTable at runtime (or, to be totally pedantic HashTable<?,?>)

like image 26
Shivan Dragon Avatar answered Nov 15 '22 10:11

Shivan Dragon