Java 将大字符串流式传输到JAXB
我的JAXB层次结构中有一个域对象,它必须表示为逗号分隔的值文本。不幸的是,显式构造CSVJava 将大字符串流式传输到JAXB,java,xml,jaxb,Java,Xml,Jaxb,我的JAXB层次结构中有一个域对象,它必须表示为逗号分隔的值文本。不幸的是,显式构造CSV字符串的成本非常高,因此这不是一个选项 我创建了一个自定义的@XmlJavaTypeAdapter,它返回一个数据处理程序(根据),但它总是将数据写入BASE64中。。。但我要保留一个遗留API,它需要ASCII字符串。更改DataHandler的MIME不会更改编码,但会影响XSD中包含的对象的定义 有没有办法设置DataHandler(或任何其他支持的Java类型)以从流式输入返回未编码的字符串 我还考
字符串
的成本非常高,因此这不是一个选项
我创建了一个自定义的@XmlJavaTypeAdapter
,它返回一个数据处理程序
(根据),但它总是将数据写入BASE64中。。。但我要保留一个遗留API,它需要ASCII字符串。更改DataHandler
的MIME不会更改编码,但会影响XSD中包含的对象的定义
有没有办法设置DataHandler
(或任何其他支持的Java类型)以从流式输入返回未编码的字符串
我还考虑返回一个
对象(实际上是CharacterData
),但这需要实现公共字符串getData()
。。。需要我显式地构造我正在尝试流式传输的字符串。以防没有人提出与DataHanler
相关的解决方案。。。以下只是一个不涉及DataHandler
的“解决方案”的替代方案。它需要访问封送员
- 修改XML类型适配器以不返回内容,而是返回一种短地址以获取流数据(例如文件名)
- 定义如下所示的XMLStreamWriter包装器:。覆盖
writeStarElement
和writeCharacters
以拦截对CSV元素的startElement
调用以及紧接其后的writeCharacters
- 传递给特定调用
writeCharacters
的数据将是获取流数据的地址。将其分块流式传输到包装好的XMLStreamWriter的WriteCharacter
以防没有人提出与DataHanler相关的解决方案。。。以下只是一个不涉及DataHandler
的“解决方案”的替代方案。它需要访问封送员
- 修改XML类型适配器以不返回内容,而是返回一种短地址以获取流数据(例如文件名)
- 定义如下所示的XMLStreamWriter包装器:。覆盖
writeStarElement
和writeCharacters
以拦截对CSV元素的startElement
调用以及紧接其后的writeCharacters
- 传递给特定调用
writeCharacters
的数据将是获取流数据的地址。将其分块流式传输到包装好的XMLStreamWriter的WriteCharacter
我不太明白为什么显式构造CSV字符串(使用StringBuilder)要比使用JAXB内置的成本更高
如果性能是您的限制因素,那么我认为您应该考虑创建自定义序列化器(例如,基于StrugBueDever)和SAX处理程序来解析XML。p>
如果您有权更改协议,那么您可能想签出,并且-它们的维护要多一些,但是如果您追求的是性能,那么这些应该更快
和往常一样,您应该使用这两种方法进行A/B性能测试,然后再将任何内容变成石头;)
回到原始主题,下面是一个关于如何使用自定义适配器的示例:
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.junit.Test;
public class Example
{
public String serialize( DataObject d ) throws JAXBException {
StringWriter buffer = new StringWriter();
JAXBContext.newInstance(DataObject.class).createMarshaller().marshal(d, buffer);
return buffer.toString();
}
@Test
public void testSerialize( ) throws JAXBException {
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><dataObject>"
+ "<FirstField>field1 content with special characters &<>'\"</FirstField>"
+ "<Second><!CDATA[[ <!-- now we're just nasty --> ]]></Second>"
+ "<Custom>a,b,c</Custom></dataObject>";
assertEquals(expected, serialize(new DataObject()).replaceAll("(\r)?\n(\r)?", "\n"));
}
}
@XmlRootElement
@XmlAccessorType( XmlAccessType.FIELD )
class DataObject
{
@XmlElement( name = "FirstField" )
private final String field1 = "field1 content with special characters &<>'\"";
@XmlElement( name = "Second" )
private final String field2 = "<!CDATA[[ <!-- now we're just nasty --> ]]>";
@XmlElement( name = "Custom" )
@XmlJavaTypeAdapter( value = CustomAdapter.class )
// you can move this over the type
private final CustomType type = new CustomType("a", "b", "c");
}
@XmlAccessorType( XmlAccessType.FIELD )
class CustomType
{
private final String a;
private final String b;
private final String c;
public CustomType( String a, String b, String c ) {
this.a = a;
this.b = b;
this.c = c;
}
public String getA( ) {
return a;
}
public String getB( ) {
return b;
}
public String getC( ) {
return c;
}
}
class CustomAdapter extends XmlAdapter<String, CustomType>
{
@Override
public String marshal( CustomType v ) throws Exception {
return String.format("%s,%s,%s", v.getA(), v.getB(), v.getC());
}
@Override
/** Please don't use this in PROD :> */
public CustomType unmarshal( String v ) throws Exception {
String[] split = v.split(",");
return new CustomType(split[ 0 ], split[ 1 ], split[ 2 ]);
}
}
导入静态org.junit.Assert.assertEquals;
导入java.io.StringWriter;
导入javax.xml.bind.JAXBContext;
导入javax.xml.bind.JAXBException;
导入javax.xml.bind.annotation.XmlAccessType;
导入javax.xml.bind.annotation.XmlAccessorType;
导入javax.xml.bind.annotation.xmlement;
导入javax.xml.bind.annotation.XmlRootElement;
导入javax.xml.bind.annotation.adapters.XmlAdapter;
导入javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
导入org.junit.Test;
公开课范例
{
公共字符串序列化(DataObject d)引发JAXBEException{
StringWriter缓冲区=新StringWriter();
newInstance(DataObject.class).createMarshaller().Marshall(d,缓冲区);
返回buffer.toString();
}
@试验
public void testSerialize()抛出jaxbeexception{
字符串应为“”
+“具有特殊字符的字段1内容(&;”\“”
+“!CDATA[[!--现在我们很讨厌--]”
+“a、b、c”;
assertEquals(应为序列化(新数据对象()).replaceAll((\r)?\n(\r)?“,”\n”);
}
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
类数据对象
{
@xmlement(name=“FirstField”)
私有最终字符串field1=“带有特殊字符的field1内容&'\”;
@xmlement(name=“Second”)
专用最终字符串字段2=“]]>”;
@xmlement(name=“自定义”)
@XmlJavaTypeAdapter(值=CustomAdapter.class)
//您可以将其移到类型上
私有最终定制类型=新定制类型(“a”、“b”、“c”);
}
@XmlAccessorType(XmlAccessType.FIELD)
类自定义类型
{
私人最终字符串a;
私有最终字符串b;
私有最终字符串c;
公共自定义类型(字符串a、字符串b、字符串c){
这个a=a;
这个.b=b;
这个.c=c;
}
公共字符串getA(){
返回a;
}
公共字符串getB(){
返回b;
}
公共字符串getC(){
返回c;
}
}
类CustomAdapter扩展了XmlAdapter
{
@凌驾
公共字符串封送处理(CustomType v)引发异常{
返回String.format(“%s,%s,%s”,v.getA(),v.getB(),v.getC());
}
@凌驾
/**请不要在产品中使用此选项:>*/
公共CustomType解组(字符串v)引发异常{
字符串[]split=v.split(“,”);
返回新的CustomType(拆分)