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.
I think your best bet is to create an xml schema that reflects what you want and then run xjc on it. This way you have some control over what the xml will look like w/o getting into the guts of JaxB. http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/jaxb/xjc.html
You can then translate your HashTable to the generated object and pass it to this variation of your static method.
Unfortunately, JAXB is not able to directly serialize a
Map
orHashMap
instance directly. Instead, you'll have to do some sort of translation from aMap
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 aMap
.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 pedanticHashTable<?,?>
)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.
You will need to create a wrapper class to hold onto the
Hashtable
:Then you can do the following:
This will produce the following output:
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 usingHashMap
is the common replacement.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: