How to serialize a 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 a bit puzzled by this task.
I saw 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(); }
What is called like this: ObjectToXml(o, ClassOfO.class)
, but the HashTable<String, String>.class
is wrong (I already know that).
Can a Java guru show me how to call this code? A suggestion of a simpler implementation (along with an example call, of course) is also welcome.
Thanks.
You will need to create a wrapper class to host on 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 lead to the following conclusion:
<?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>
Remarks
JAXBContext
is a thread-safe object and must be created once and reused.Hashtable
synchronized, if you do not need it, then usingHashMap
is a common replacement.- The convention is to run Java method names with a lowercase letter.
Display Setting
You can use the XmlAdapter
in JAXB to customize the display of any class. Below is a link to a blog post where I demonstrate how to do this:
Unfortunately, JAXB cannot directly serialize a Map
or HashMap
instance directly. Instead, you will need to do some translation from Map
to a list of records that have a key and value. Try exploring this stack overflow issue and see if it can help you. This problem shows up on Google, and the sad answer is that JAXB does not know how to serialize Map
.
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 agree that “perplexity” is a good description of the perception of the non-obviousness of a task.
Although you may be familiar with C # generated generators, Java generators are for compile time only, they go away at runtime. So at runtime, even if you have an instance with generics installed (like String for a HashTable) at runtime, these generics go away, so all you can do is get a thing class (HashTable here) and not the actual shared types (line here). In short: compilation time Hashtable<String,String>
becomes a HashTable at runtime (or, to be completely pedantic, HashTable<?,?>
)
I believe that it is best to create an xml schema that reflects what you want and then run xjc. This way, you have some control over what xml will look like without getting into the guts of JaxB. http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/jaxb/xjc.html
Then you can transfer your HashTable to the generated object and pass it to this variant of your static method.
public static <T> String ObjectToXml(T object) throws JAXBException { JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass()); StringWriter writerTo = new StringWriter(); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(object, writerTo); return writerTo.toString(); }