Document to String y viceversa

	public static String documentToString(Document doc) {
		return sourceToString(new DOMSource(doc));
	}
	
	public static String sourceToString(Source source) {
		try {
			StringWriter sw = new StringWriter();
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer transformer = tf.newTransformer();
			transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
			transformer.setOutputProperty(OutputKeys.METHOD, "xml");
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

			transformer.transform(source, new StreamResult(sw));
			return sw.toString();
		} catch (Exception ex) {
			throw new RuntimeException("Error converting to String", ex);
		}
	}
	
	public static Source toSource(String xml){
		return new StreamSource(new StringReader(xml));
	}
	
	public static Document stringToDocument(String xml) {
		Document doc = null;
		try {
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			doc = db.parse( new InputSource( new StringReader( xml ) ) ); 
		} catch (Exception e) {
			throw new RuntimeException("Error converting to String", e);
		}
		return doc;
	}
	
	public static Source stringToDocumentToSource(String xml) {
		return new DOMSource(stringToDocument(xml));
	}
	
	public static Source stringToSource(String xml) {
		return new StreamSource(new StringReader(xml));
	}

¿Porque es importante el Source?. A la hora de realizar el marshall/unmarshall de objetos y strings JAXB siempre quiere datos de tipo Source.

	public Object xmlToObject(String xml) throws Exception {
		ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes(getEncoding()));
		StreamSource source = new StreamSource(bais);
		return xmlToObject(source);
	}
	
	public Object xmlToObject(Source source) throws Exception {
		return jaxb2Marshaller.unmarshal(source);
	}
Document to String y viceversa

JAXB y CXF

Recientemente me encuentro en proyectos donde por un lado tengo unos XSD que he transformado en clases y un servicio web que usa estas clases para comunicarse.

En mi modulo de generacion de clases, para poder realizar el marshal/unmarshal he usado spring con OXM. Mediante configuracion he indicado a Spring, donde estaban los XSD, para las validaciones y donde estaban las clases que tenia que tener en el contexto. Estos son los application context:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="
		http://www.springframework.org/schema/util 
		http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
        
    <import resource="classpath*:spring/spring-xsd-marshall.xml" />
    
	<util:constant id="m_jaxbFormattedOutput" static-field="javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT" />
	<util:constant id="m_jaxbEncoding" static-field="javax.xml.bind.Marshaller.JAXB_ENCODING" />

	<util:map id="marshallerPropertiesMap">
		<entry key-ref="m_jaxbEncoding" value="UTF-8" />
		<entry key-ref="m_jaxbFormattedOutput">
			<value type="java.lang.Boolean">true</value>
		</entry>
	</util:map>

	<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" >
		<property name="marshallerProperties" ref="marshallerPropertiesMap" />
		<property name="classesToBeBound" ref="classesToBeBoundList" />
		<property name="schemas" ref="schemasList" />
	</bean>
	
	<bean id="xmlB64Binder" class ="es.depontevedra.soa.xsd.spi.XmlB64Binder">
		<property name="encoding" value="UTF-8" />
	</bean>
	
	<bean id="xmlBinder" class ="es.depontevedra.soa.xsd.spi.XmlBinder">
		<property name="encoding" value="UTF-8" />
	</bean>

</beans>

Cada modulo en el que necesite serializar objetos, tiene que desarrollar su propio fichero de configuracion de serializacion para Spring:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="
		http://www.springframework.org/schema/util 
		http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
<!-- ESTE ES EL FICHERO QUE CONTIENE LAS CLASES QUE REALIZARAN LA SERIALIZACION -->
<!-- <import resource="classpath*:spring/spring-xsd.xml" /> -->
<!-- EN ESTE FICHERO SOLO SE INDICA LO QUE SE QUIERE SERIALIZAR -->
    
    <util:list id="schemasList">
		<value>classpath:wsdl/confirmacion-peticion.xsd</value>
		<value>classpath:wsdl/datos-especificos.xsd</value>
		<value>classpath:wsdl/peticion.xsd</value>
		<value>classpath:wsdl/respuesta.xsd</value>
		<value>classpath:wsdl/soapfaultatributos.xsd</value>
		<value>classpath:wsdl/solicitud-respuesta.xsd</value>
	</util:list>
	
	<util:list id="classesToBeBoundList">
		<value>es.map.scsp.esquemas.datosespecificos.DatosDireccionType</value>
		<value>es.map.scsp.esquemas.datosespecificos.DatosEspecificos</value>
		<value>es.map.scsp.esquemas.datosespecificos.DatosNacimiento</value>
		<value>es.map.scsp.esquemas.datosespecificos.DatosNacimientoType</value>
		<value>es.map.scsp.esquemas.datosespecificos.DatosTitular</value>
		<value>es.map.scsp.esquemas.datosespecificos.EstadoResultado</value>
		<value>es.map.scsp.esquemas.datosespecificos.Organizacion</value>
		<value>es.map.scsp.esquemas.datosespecificos.SolicitanteDatos</value>
		<value>es.map.scsp.esquemas.datosespecificos.Solicitud</value>
		
		<value>es.map.scsp.esquemas.v2.confirmacionpeticion.Atributos</value>
		<value>es.map.scsp.esquemas.v2.confirmacionpeticion.ConfirmacionPeticion</value>
		<value>es.map.scsp.esquemas.v2.confirmacionpeticion.Estado</value>
		
		<value>es.map.scsp.esquemas.v2.peticion.Atributos</value>
		<value>es.map.scsp.esquemas.v2.peticion.DatosGenericos</value>
		<value>es.map.scsp.esquemas.v2.peticion.Emisor</value>
		<value>es.map.scsp.esquemas.v2.peticion.Estado</value>
		<value>es.map.scsp.esquemas.v2.peticion.Funcionario</value>
		<value>es.map.scsp.esquemas.v2.peticion.Peticion</value>
		<value>es.map.scsp.esquemas.v2.peticion.Solicitante</value>
		<value>es.map.scsp.esquemas.v2.peticion.Solicitudes</value>
		<value>es.map.scsp.esquemas.v2.peticion.SolicitudTransmision</value>
		<value>es.map.scsp.esquemas.v2.peticion.Titular</value>
		<value>es.map.scsp.esquemas.v2.peticion.Transmision</value>
		
		<value>es.map.scsp.esquemas.v2.respuesta.Atributos</value>
		<value>es.map.scsp.esquemas.v2.respuesta.DatosGenericos</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Emisor</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Estado</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Funcionario</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Respuesta</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Solicitante</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Titular</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Transmision</value>
		<value>es.map.scsp.esquemas.v2.respuesta.TransmisionDatos</value>
		<value>es.map.scsp.esquemas.v2.respuesta.Transmisiones</value>
		
		<value>es.map.scsp.esquemas.v2.soapfaultatributos.Atributos</value>
		<value>es.map.scsp.esquemas.v2.soapfaultatributos.Estado</value>

		<value>es.map.scsp.esquemas.v2.solicitudrespuesta.Atributos</value>
		<value>es.map.scsp.esquemas.v2.solicitudrespuesta.Estado</value>
		<value>es.map.scsp.esquemas.v2.solicitudrespuesta.SolicitudRespuesta</value>
	</util:list>

</beans>

Tengo una clase en este modulo que es la encargada de realizar el Marshall/UnMarshall:

package es.depontevedra.soa.xsd.spi;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.beans.factory.annotation.Autowired;

import es.depontevedra.soa.xsd.XmlObjectBinder;

public abstract class MarshalUnmarshal implements XmlObjectBinder {

	private String encoding;

	@Autowired
	private org.springframework.oxm.jaxb.Jaxb2Marshaller jaxb2Marshaller;

	public MarshalUnmarshal() {
		super();
	}

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	public Object xmlToObject(String xml) throws Exception {
		ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes(getEncoding()));
		StreamSource source = new StreamSource(bais);
		return jaxb2Marshaller.unmarshal(source);
	}

	public String objectToXml(Object object) throws Exception {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		StreamResult result = new StreamResult(baos);
		jaxb2Marshaller.marshal(object, result);
		String xml = baos.toString(getEncoding()); 
		return xml;
	}

}
package es.depontevedra.soa.xsd.spi;

public class XmlBinder extends MarshalUnmarshal {

	public XmlBinder() {}
	
	public Object unmarshal(String xml) throws Exception {
		return xmlToObject(xml);
	}
	
	public String marshal(Object object) throws Exception {
		return objectToXml(object);
	}

}

Tambien esta la clase es.depontevedra.soa.xsd.spi.XmlB64Binder que hace lo mismo que XmlBinder pero los String son en BASE64.

Bien pues todo esto se puede hacer mucho mas sencillo:

	public String objectToXml(Object object) throws Exception {
		JAXBContext jc = JAXBContext.newInstance( "es.map.scsp.esquemas.v2.peticion:es.map.scsp.esquemas.datosespecificos:es.map.scsp.esquemas.v2.respuesta.Respuesta" );
		Marshaller marshaller = jc.createMarshaller();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		marshaller.marshal(peticion, baos);
		
		return new String( baos.toByteArray(), "UTF-8" );
	}

	public Object xmlToObject(String xml) throws Exception {
		JAXBContext jc = JAXBContext.newInstance( "es.map.scsp.esquemas.v2.peticion:es.map.scsp.esquemas.datosespecificos:es.map.scsp.esquemas.v2.respuesta.Respuesta" );
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes(getEncoding()));
		StreamSource source = new StreamSource(bais);
		return (Peticion) unmarshaller.unmarshal(source);
	}

Nota que los paquetes del contexto estan separados por dos puntos.

Habria que añadir mas codigo para las validaciones, generar clases, interfaces para las llamadas…
Cada vez que quieras realizar una accion puedes llamar a estos metodos de manera estatica, pasando por parametros los paquetes.

JAXB y CXF