SPR-6907 - JibxMarshaller - provide access to jibx's writeDocType
This commit is contained in:
parent
d207c2294d
commit
9d1c3fa9ac
|
|
@ -31,6 +31,8 @@ import javax.xml.stream.XMLStreamWriter;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
import javax.xml.transform.TransformerException;
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.Result;
|
||||||
|
import javax.xml.transform.Source;
|
||||||
import javax.xml.transform.dom.DOMResult;
|
import javax.xml.transform.dom.DOMResult;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
import javax.xml.transform.sax.SAXResult;
|
import javax.xml.transform.sax.SAXResult;
|
||||||
|
|
@ -64,6 +66,7 @@ import org.springframework.oxm.XmlMappingException;
|
||||||
import org.springframework.oxm.support.AbstractMarshaller;
|
import org.springframework.oxm.support.AbstractMarshaller;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.xml.StaxUtils;
|
import org.springframework.util.xml.StaxUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -79,7 +82,7 @@ import org.springframework.util.xml.StaxUtils;
|
||||||
*/
|
*/
|
||||||
public class JibxMarshaller extends AbstractMarshaller implements InitializingBean {
|
public class JibxMarshaller extends AbstractMarshaller implements InitializingBean {
|
||||||
|
|
||||||
private Class targetClass;
|
private Class<?> targetClass;
|
||||||
|
|
||||||
private String bindingName;
|
private String bindingName;
|
||||||
|
|
||||||
|
|
@ -89,6 +92,14 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
|
|
||||||
private Boolean standalone;
|
private Boolean standalone;
|
||||||
|
|
||||||
|
private String docTypeRootElementName;
|
||||||
|
|
||||||
|
private String docTypeSystemId;
|
||||||
|
|
||||||
|
private String docTypePublicId;
|
||||||
|
|
||||||
|
private String docTypeInternalSubset;
|
||||||
|
|
||||||
private IBindingFactory bindingFactory;
|
private IBindingFactory bindingFactory;
|
||||||
|
|
||||||
private TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
private TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||||
|
|
@ -97,7 +108,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
/**
|
/**
|
||||||
* Set the target class for this instance. This property is required.
|
* Set the target class for this instance. This property is required.
|
||||||
*/
|
*/
|
||||||
public void setTargetClass(Class targetClass) {
|
public void setTargetClass(Class<?> targetClass) {
|
||||||
this.targetClass = targetClass;
|
this.targetClass = targetClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,9 +140,54 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
this.standalone = standalone;
|
this.standalone = standalone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the root element name for the DTD declaration written when marshalling. By default, this is
|
||||||
|
* {@code null} (i.e. no DTD declaration is written). If set to a value, the system ID or public ID also need to
|
||||||
|
* be set.
|
||||||
|
*
|
||||||
|
* @see #setDocTypeSystemId(String)
|
||||||
|
* @see #setDocTypePublicId(String)
|
||||||
|
*/
|
||||||
|
public void setDocTypeRootElementName(String docTypeRootElementName) {
|
||||||
|
this.docTypeRootElementName = docTypeRootElementName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the system Id for the DTD declaration written when marshalling. By default, this is
|
||||||
|
* {@code null}. Only used when the root element also has been set. Set either this property or
|
||||||
|
* {@code docTypePublicId}, not both.
|
||||||
|
*
|
||||||
|
* @see #setDocTypeRootElementName(String)
|
||||||
|
*/
|
||||||
|
public void setDocTypeSystemId(String docTypeSystemId) {
|
||||||
|
this.docTypeSystemId = docTypeSystemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the public Id for the DTD declaration written when marshalling. By default, this is
|
||||||
|
* {@code null}. Only used when the root element also has been set. Set either this property or
|
||||||
|
* {@code docTypeSystemId}, not both.
|
||||||
|
*
|
||||||
|
* @see #setDocTypeRootElementName(String)
|
||||||
|
*/
|
||||||
|
public void setDocTypePublicId(String docTypePublicId) {
|
||||||
|
this.docTypePublicId = docTypePublicId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal subset Id for the DTD declaration written when marshalling. By default, this is
|
||||||
|
* {@code null}. Only used when the root element also has been set.
|
||||||
|
*
|
||||||
|
* @see #setDocTypeRootElementName(String)
|
||||||
|
*/
|
||||||
|
public void setDocTypeInternalSubset(String docTypeInternalSubset) {
|
||||||
|
this.docTypeInternalSubset = docTypeInternalSubset;
|
||||||
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() throws JiBXException {
|
public void afterPropertiesSet() throws JiBXException {
|
||||||
Assert.notNull(this.targetClass, "targetClass is required");
|
Assert.notNull(this.targetClass, "'targetClass' is required");
|
||||||
|
Assert.isTrue(!(StringUtils.hasLength(docTypePublicId) && StringUtils.hasLength(docTypeSystemId)),
|
||||||
|
"Set either 'docTypePublicId' or 'docTypeSystemId'; not both");
|
||||||
if (StringUtils.hasLength(this.bindingName)) {
|
if (StringUtils.hasLength(this.bindingName)) {
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Configured for target class [" + this.targetClass + "] using binding [" + this.bindingName + "]");
|
logger.info("Configured for target class [" + this.targetClass + "] using binding [" + this.bindingName + "]");
|
||||||
|
|
@ -167,7 +223,8 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
throws XmlMappingException, IOException {
|
throws XmlMappingException, IOException {
|
||||||
try {
|
try {
|
||||||
IMarshallingContext marshallingContext = createMarshallingContext();
|
IMarshallingContext marshallingContext = createMarshallingContext();
|
||||||
marshallingContext.marshalDocument(graph, this.encoding, this.standalone, outputStream);
|
marshallingContext.startDocument(this.encoding, this.standalone, outputStream);
|
||||||
|
marshalDocument(marshallingContext, graph);
|
||||||
}
|
}
|
||||||
catch (JiBXException ex) {
|
catch (JiBXException ex) {
|
||||||
throw convertJibxException(ex, true);
|
throw convertJibxException(ex, true);
|
||||||
|
|
@ -178,13 +235,23 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
|
protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
|
||||||
try {
|
try {
|
||||||
IMarshallingContext marshallingContext = createMarshallingContext();
|
IMarshallingContext marshallingContext = createMarshallingContext();
|
||||||
marshallingContext.marshalDocument(graph, this.encoding, this.standalone, writer);
|
marshallingContext.startDocument(this.encoding, this.standalone, writer);
|
||||||
|
marshalDocument(marshallingContext, graph);
|
||||||
}
|
}
|
||||||
catch (JiBXException ex) {
|
catch (JiBXException ex) {
|
||||||
throw convertJibxException(ex, true);
|
throw convertJibxException(ex, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void marshalDocument(IMarshallingContext marshallingContext, Object graph) throws IOException,
|
||||||
|
JiBXException {
|
||||||
|
if (StringUtils.hasLength(docTypeRootElementName)) {
|
||||||
|
IXMLWriter xmlWriter = marshallingContext.getXmlWriter();
|
||||||
|
xmlWriter.writeDocType(docTypeRootElementName, docTypeSystemId, docTypePublicId, docTypeInternalSubset);
|
||||||
|
}
|
||||||
|
marshallingContext.marshalDocument(graph);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
|
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
|
||||||
try {
|
try {
|
||||||
|
|
@ -198,20 +265,16 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Unsupported Marshalling
|
// Unsupported Marshalling
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void marshalDomNode(Object graph, Node node) throws XmlMappingException {
|
protected void marshalDomNode(Object graph, Node node) throws XmlMappingException {
|
||||||
try {
|
try {
|
||||||
// JiBX does not support DOM natively, so we write to a buffer first, and transform that to the Node
|
// JiBX does not support DOM natively, so we write to a buffer first, and transform that to the Node
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
Result result = new DOMResult(node);
|
||||||
marshalOutputStream(graph, os);
|
transformAndMarshal(graph, result);
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
|
||||||
Transformer transformer = this.transformerFactory.newTransformer();
|
|
||||||
transformer.transform(new StreamSource(is), new DOMResult(node));
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (IOException ex) {
|
||||||
throw new MarshallingFailureException("JiBX marshalling exception", ex);
|
throw new MarshallingFailureException("JiBX marshalling exception", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -221,17 +284,28 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
throws XmlMappingException {
|
throws XmlMappingException {
|
||||||
try {
|
try {
|
||||||
// JiBX does not support SAX natively, so we write to a buffer first, and transform that to the handlers
|
// JiBX does not support SAX natively, so we write to a buffer first, and transform that to the handlers
|
||||||
|
SAXResult saxResult = new SAXResult(contentHandler);
|
||||||
|
saxResult.setLexicalHandler(lexicalHandler);
|
||||||
|
transformAndMarshal(graph, saxResult);
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new MarshallingFailureException("JiBX marshalling exception", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transformAndMarshal(Object graph, Result result) throws IOException {
|
||||||
|
try {
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
marshalOutputStream(graph, os);
|
marshalOutputStream(graph, os);
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
||||||
Transformer transformer = this.transformerFactory.newTransformer();
|
Transformer transformer = this.transformerFactory.newTransformer();
|
||||||
SAXResult saxResult = new SAXResult(contentHandler);
|
transformer.transform(new StreamSource(is), result);
|
||||||
saxResult.setLexicalHandler(lexicalHandler);
|
|
||||||
transformer.transform(new StreamSource(is), saxResult);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (TransformerException ex) {
|
||||||
throw new MarshallingFailureException("JiBX marshalling exception", ex);
|
throw new MarshallingFailureException(
|
||||||
|
"Could not transform to [" + ClassUtils.getShortName(result.getClass()) + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -295,13 +369,9 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
@Override
|
@Override
|
||||||
protected Object unmarshalDomNode(Node node) throws XmlMappingException {
|
protected Object unmarshalDomNode(Node node) throws XmlMappingException {
|
||||||
try {
|
try {
|
||||||
Transformer transformer = transformerFactory.newTransformer();
|
return transformAndUnmarshal(new DOMSource(node));
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
|
||||||
transformer.transform(new DOMSource(node), new StreamResult(os));
|
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
|
||||||
return unmarshalInputStream(is);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (IOException ex) {
|
||||||
throw new UnmarshallingFailureException("JiBX unmarshalling exception", ex);
|
throw new UnmarshallingFailureException("JiBX unmarshalling exception", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -309,15 +379,20 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
|
||||||
@Override
|
@Override
|
||||||
protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
|
protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
|
||||||
throws XmlMappingException, IOException {
|
throws XmlMappingException, IOException {
|
||||||
|
return transformAndUnmarshal(new SAXSource(xmlReader, inputSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object transformAndUnmarshal(Source source) throws IOException {
|
||||||
try {
|
try {
|
||||||
Transformer transformer = this.transformerFactory.newTransformer();
|
Transformer transformer = transformerFactory.newTransformer();
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
transformer.transform(new SAXSource(xmlReader, inputSource), new StreamResult(os));
|
transformer.transform(source, new StreamResult(os));
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
||||||
return unmarshalInputStream(is);
|
return unmarshalInputStream(is);
|
||||||
}
|
}
|
||||||
catch (TransformerException ex) {
|
catch (TransformerException ex) {
|
||||||
throw new UnmarshallingFailureException("JiBX unmarshalling exception", ex);
|
throw new MarshallingFailureException(
|
||||||
|
"Could not transform from [" + ClassUtils.getShortName(source.getClass()) + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,16 @@ public class JibxMarshallerTests extends AbstractMarshallerTests {
|
||||||
writer.toString().startsWith("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>"));
|
writer.toString().startsWith("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dtd() throws Exception {
|
||||||
|
((JibxMarshaller) marshaller).setDocTypeRootElementName("flights");
|
||||||
|
((JibxMarshaller) marshaller).setDocTypeSystemId("flights.dtd");
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
marshaller.marshal(flights, new StreamResult(writer));
|
||||||
|
assertTrue("doc type not written",
|
||||||
|
writer.toString().contains("<!DOCTYPE flights SYSTEM \"flights.dtd\">"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSupports() throws Exception {
|
public void testSupports() throws Exception {
|
||||||
assertTrue("JibxMarshaller does not support Flights", marshaller.supports(Flights.class));
|
assertTrue("JibxMarshaller does not support Flights", marshaller.supports(Flights.class));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue