Подтвердить что ты не робот

Как маршалировать объект через JAXB без какой-либо информации об этом?

У меня есть объект value, который имеет какой-то тип, либо @XmlRootElement -незаменит, либо нет. Я хочу объединить его в XML:

String value1 = "test";
assertEquals("<foo>test</foo>", toXml("foo", value1));
// ...
@XmlRootElement
class Bar {
  public String bar = "test";
}
assertEquals("<foo><bar>test</bar></foo>", toXml("foo", new Bar()));

Могу ли я сделать это с существующими средствами JAXB, или я должен создать какой-то пользовательский анализатор?

4b9b3361

Ответ 1

Вы можете использовать JAXBIntrospector для выполнения следующих действий:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;

public class Demo {


    public static void main(String[] args) throws Exception {
        Object value = "Hello World";
        //Object value = new Bar();

        JAXBContext jc = JAXBContext.newInstance(String.class, Bar.class);
        JAXBIntrospector introspector = jc.createJAXBIntrospector();
        Marshaller marshaller = jc.createMarshaller();
        if(null == introspector.getElementName(value)) {
            JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), Object.class, value);
            marshaller.marshal(jaxbElement, System.out);
        } else {
            marshaller.marshal(value, System.out);
        }
    }

    @XmlRootElement
    public static class Bar {

    }

}

При использовании вышеуказанного кода при сортировке JAXBElement он будет иметь атрибут xsi: type, соответствующий соответствующему типу схемы:

<ROOT 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">Hello World</ROOT>

Чтобы исключить квалификацию, вы можете просто изменить строку, которая создает JAXBElement, чтобы:

JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), value.getClass(), value);

Это приведет к следующему XML:

<ROOT>Hello World</ROOT>

Ответ 2

Вот как маршал value1, который является String. Вы можете передать yourObject.getClass() в конструктор JAXBElement и value1:

try {
    JAXBContext jc = JAXBContext.newInstance();
    Marshaller m = jc.createMarshaller();
    String value1 = "test";
    JAXBElement jx = new JAXBElement(new QName("foo"), value1.getClass(), value1);
    m.marshal(jx, System.out);
} catch (JAXBException ex) {
    ex.printStackTrace();
}

Это работает без использования @XmlRootElement. Результатом приведенного выше кода было:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><foo>test</foo>

С другой стороны, это не будет работать с объектом Bar: javax.xml.bind.JAXBException: myPackage.Bar is not known to this context. Однако вы можете получить значение изнутри Bar и создать JAXBElement с этим, а не с самим объектом.

Ответ 3

Я не нашел хорошего общего способа сделать это. Вот мое общее решение.

import javax.xml.bind.*;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;

public class XMLConverter {

    /**
     * Serialize object to XML string
     * @param object object
     * @param <T> type
     * @return
     */
    public static <T> String marshal(T object) {
        try {
            StringWriter stringWriter = new StringWriter();
            JAXBContext jc = JAXBContext.newInstance(object.getClass());
            Marshaller m = jc.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            QName qName = new QName(object.getClass().getCanonicalName(), object.getClass().getSimpleName());
            JAXBElement<T> root = new JAXBElement(qName, object.getClass(), object);

            m.marshal(root, stringWriter);
            return stringWriter.toString();
        } catch (Exception e) {
            // log the exception
        }
        return null;
    }

    /**
     * Deserialize XML string back to object
     * @param content XML content
     * @param clasz class
     * @param <T> type
     * @return
     */
    public static <T> T unMarshal(final String content, final Class<T> clasz) {
        try {
            JAXBContext jc = JAXBContext.newInstance(clasz);
            Unmarshaller u = jc.createUnmarshaller();
            return u.unmarshal(new StreamSource(new StringReader(content)), clasz).getValue();
        } catch (Exception e) {
            // log the exception
        }
        return null;
    }

}

Ответ 4

Если он не аннотируется с помощью @XmlRootElement, то JAXB не имеет достаточной информации для его маршалирования. Сначала вам нужно обернуть его в JAXBElement.

Не могли бы вы задуматься, как обернуть объект в соответствующем JAXBElement?