Java 如何在没有任何信息的情况下通过JAXB封送对象?

Java 如何在没有任何信息的情况下通过JAXB封送对象?,java,xml,jaxb,Java,Xml,Jaxb,我有一个对象值,它是某种类型的,要么是@XmlRootElement-注释的,要么不是注释的。我想将其封送到XML中: String value1 = "test"; assertEquals("<foo>test</foo>", toXml("foo", value1)); // ... @XmlRootElement class Bar { public String bar = "test"; } assertEquals("<foo><bar

我有一个对象
,它是某种类型的,要么是
@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()));
String value1=“测试”;
资产质量(“测试”,toXml(“foo”,value1));
// ...
@XmlRootElement
分类栏{
公共字符串bar=“test”;
}
assertEquals(“test”,toXml(“foo”,newbar());

我可以使用JAXB现有的工具来完成它,还是应该创建一些自定义分析器?

如果它没有使用
@XmlRootElement
注释,那么JAXB没有足够的信息来封送它。您需要首先将其包装在
JAXBElement


您是否可以做一些反思性的工作来了解如何将对象包装到适当的
JAXBElement

以下是如何封送
value1
,它是一个
字符串。您可以将
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对此上下文不了解。但是,您可以从
栏中获取值,并使用该值创建
JAXBElement
,而不是对象本身。

您可以利用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 {

    }

}
使用上面的代码,当封送JAXBEElement时,它将使用对应于适当模式类型的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>
这将产生以下XML:

<ROOT>Hello World</ROOT>
你好,世界

我没有找到任何好的通用方法。这是我的通用解决方案

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

}
import javax.xml.bind.*;
导入javax.xml.namespace.QName;
导入javax.xml.transform.stream.StreamSource;
导入java.io.StringReader;
导入java.io.StringWriter;
公共类XML转换器{
/**
*将对象序列化为XML字符串
*@param对象
*@param类型
*@返回
*/
公共静态字符串封送处理(T对象){
试一试{
StringWriter StringWriter=新StringWriter();
JAXBContext jc=JAXBContext.newInstance(object.getClass());
Marshaller m=jc.createMarshaller();
m、 setProperty(Marshaller.JAXB_格式的_输出,Boolean.TRUE);
QName QName=新的QName(object.getClass().getCanonicalName(),object.getClass().getSimpleName());
JAXBElement root=newjaxbelement(qName,object.getClass(),object);
m、 封送员(root,stringWriter);
返回stringWriter.toString();
}捕获(例外e){
//记录异常
}
返回null;
}
/**
*将XML字符串反序列化回对象
*@param content XML content
*@param-clasz类
*@param类型
*@返回
*/
公共静态T解组(最终字符串内容,最终类clasz){
试一试{
JAXBContext jc=JAXBContext.newInstance(clasz);
解组器u=jc.createUnmarshaller();
返回u.unmarshal(新StreamSource(新StringReader(content)),clasz.getValue();
}捕获(例外e){
//记录异常
}
返回null;
}
}

查看我的答案,了解如何使用JAXBIntrospector避免任何反射调用。工作非常完美!也许您知道如何去掉
xsi:type
属性?这就是我对
字符串
对象得到的结果:
(239)555 2390
@Vincenzo我已经更新了我的答案,详细说明了如何消除xsi:type属性。@BlaiseDoughan请查看此问题:如果使用object.getClass().getCanonicalName(),则名称空间错误
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;
    }

}