如何使用JAXB将HashTable<String, String>序列化为XML?

6
我会尝试使用JAXB将HashTable<String, String>序列化为XML,这与我之前的C#经验不同,让我感到困惑。
我看到了以下代码:
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();
}

如下所示调用:ObjectToXml(o, ClassOfO.class),但是HashTable<String, String>.class 是错误的(这一点我已经知道了)。

Java高手能否向我展示如何调用此代码?如果提供一个更简单的实现方法(当然还包括调用示例),那就最好不过了。

谢谢。

5个回答

6
您需要创建一个包装类来保存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;
    }

}

然后,您可以执行以下操作:
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();
    }

}

这将生成以下输出:
<?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>

注意事项

  • JAXBContext 是一个线程安全的对象,应该创建一次并重复使用。
  • Hashtable 是同步的,如果您不需要它,可以使用 HashMap 进行常见替换。
  • 惯例是使用小写字母开头来命名 Java 方法。

自定义映射

您可以在 JAXB 中使用 XmlAdapter 来自定义任何类的映射。以下是我在博客上演示如何执行此操作的链接:


一个比适配器更简单且易于维护的解决方案,是将诸如一对数组之类的简单类型存储在文件中,然后通过循环遍历数组元素,在读取文件时构建映射。 - Richard Whitehead

4

不幸的是,JAXB 无法直接序列化 MapHashMap 实例。相反,您需要将 Map 转换为具有键和值的条目列表。尝试查看 这个 Stack Overflow 问题,看看它是否能帮助您。这个问题在谷歌上出现了很多次,令人遗憾的答案是 JAXB 不知道如何序列化 Map


2
JAXB确实对映射有默认设置(请参见https://dev59.com/x1vUa4cB1Zd3GeqPu5Rx#7534671)。您所描述的策略是必要的,以指定除默认设置之外的映射。 - bdoughan

3

1

我认为你最好的选择是创建一个反映你想要的 XML 结构的 XML Schema,然后在其上运行 xjc。这样,你就可以在不涉及 JaxB 的内部结构的情况下对 XML 的外观进行一些控制。 http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/jaxb/xjc.html

然后,你可以将你的 HashTable 转换为生成的对象,并将其传递给你的静态方法的这个变体。

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();
    }

1

虽然您可能熟悉C#的具体化泛型,但Java的泛型仅在编译时存在,运行时会消失。这就是为什么即使在运行时有已经建立了泛型实例(例如HashTable的String),这些泛型也会消失,因此您只能获取该对象的类(这里是HashTable),而无法获取实际的泛型类型(这里是String)。简而言之:编译时的Hashtable<String,String>在运行时变成了HashTable(或者更准确地说是HashTable<?,?>)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接