Как сериализовать HashTable <String, String> в XML с использованием JAXB? - PullRequest
6 голосов
/ 24 сентября 2011

Я пытаюсь использовать JAXB для сериализации HashTable<String, String> в XML. Я очень новичок в Java (пришёл из 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 голосов
/ 24 сентября 2011

Вам нужно будет создать класс-оболочку для хранения 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 со строчной буквы.

Настройка сопоставления

Вы можете использовать XmlAdapter в JAXB для настройки отображения любого класса. Ниже приведена ссылка на пост в моем блоге, где я демонстрирую, как это сделать:

4 голосов
/ 24 сентября 2011

К сожалению, JAXB не может напрямую сериализовать экземпляр Map или HashMap напрямую. Вместо этого вам придется выполнить какой-то перевод из Map в список записей, которые имеют ключ и значение. Попробуйте посмотреть этот вопрос о переполнении стека и посмотрите, поможет ли он вам. Эта проблема часто появляется в Google, и печальный ответ заключается в том, что JAXB не знает, как сериализовать Map.

3 голосов
/ 24 сентября 2011

Ба! Если бы вы гуглили только на jaxb и hashmap , вы бы прямо нашли это: http://download.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html

Но, да, я вроде согласен с тем, что «недоумение» является хорошим описанием ощущения неочевидности задачи.

1 голос
/ 24 сентября 2011

Я думаю, что вам лучше всего создать XML-схему, которая отражает то, что вы хотите, а затем запустить xjc.Таким образом, у вас есть некоторый контроль над тем, как будет выглядеть XML без попадания в кишку JaxB.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 голос
/ 24 сентября 2011

Хотя вы, возможно, знакомы с обобщенными обобщениями C #, обобщенные версии Java предназначены только для времени компиляции, но исчезают во время выполнения. Вот почему во время выполнения, даже если у вас есть экземпляр с установленными обобщениями (например, String для HashTable), во время выполнения эти обобщенные элементы исчезают, поэтому все, что вы можете сделать, это получить класс этой вещи (здесь HashTable), а не фактический обобщенный. типы (строка здесь). Вкратце: время компиляции Hashtable<String,String> становится HashTable во время выполнения (или, чтобы быть полностью педантичным HashTable<?,?>)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...