Как было сказано во введении, маршализатор сериализует объект в XML, а демаршализатор десериализует XML-поток в объект. В этом разделе описаны два интерфейса Spring, используемые для этой цели.

Основные сведения о Marshaller

Spring абстрагирует все операции маошализатора за интерфейсом org.springframework.oxm.Marshaller, основной метод которого представлен ниже:

public interface Marshaller {
    /**
     * Маршализируем объектный граф с заданным корнем в предоставленный Result.
     */
    void marshal(Object graph, Result result) throws XmlMappingException, IOException;
}

Интерфейс Marshaller имеет один главный метод, который маршализирует данный объект в данный javax.xml.transform.Result. В результате получился интерфейс тегов, который в основном представляет собой абстракцию вывода XML. Конкретные реализации обертывают различные XML-представления, как показано в следующей таблице:

Реализация результата Обертывает представление XML

DOMResult

org.w3c.dom.Node

SAXResult

org.xml.sax.ContentHandler

StreamResult

java.io.File, java.io.OutputStream, или java.io.Writer

Хотя метод marshal() принимает в качестве первого параметра обычный объект, большинство реализаций Marshaller не могут работать с произвольными объектами. Вместо этого класс объекта должен быть отображен в файле отображения, помечен аннотацией, зарегистрирован в маршализаторе или иметь общий базовый класс. Обратитесь к последующим разделам этой главы, чтобы определить, каким образом ваша O-X-технология упраляет этим процессом.

Общие сведения о Unmarshaller

Аналогично Marshaller, у нас есть интерфейс org.springframework.oxm.Unmarshaller, который показан в следующем листинге:

public interface Unmarshaller {
    /**
     * Демаршализируем предоставленный Source в объектный граф.
     */
    Object unmarshal(Source source) throws XmlMappingException, IOException;
}

Этот интерфейс также имеет один метод, который читает из заданного javax.xml.transform.Source (абстракция ввода XML) и возвращает прочитанный объект. Как и в случае с Result, Source – это интерфейс тегов, который имеет три конкретные реализации. Каждая из них имеет свое XML-представление, как показано в следующей таблице:

Реализация интерфейса Source Обертывает представление XML

DOMSource

org.w3c.dom.Node

SAXSource

org.xml.sax.InputSource, и org.xml.sax.XMLReader

StreamSource

java.io.File, java.io.InputStream, или java.io.Reader

Несмотря на то, что существует два отдельных интерфейса маршализации (Marshaller и Unmarshaller), все реализации в Spring-WS реализуют оба в одном классе. Это означает, что можно связать один класс маршализатора и ссылаться на него как на маршализатор, так и как на демаршализатор в вашем applicationContext.xml.

Основные сведения о XmlMappingException

Spring преобразует исключения из базового инструмента отображения O-X в собственную иерархию исключений с XmlMappingException в качестве корневого исключения. Эти исключения времени выполнения оборачивают исходное исключение, поэтому информация не теряется.

Кроме того, MarshallingFailureException и UnmarshallingFailureException обеспечивают различие между операциями маршализации и демаршализации, даже если базовый инструмент O-X-отображения этого не делает.

Иерархия исключений O-X-отображения показана на следующем рисунке:

6.3. Использование Marshaller и Unmarshaller

Вы можете использовать OXM из Spring в самых разных ситуациях. В следующем примере он используется для маршализации настроек приложения, управляемого Spring, в XML-файл. В следующем примере используется простой JavaBean для представления настроек:

Java
public class Settings {
    private boolean fooEnabled;
    public boolean isFooEnabled() {
        return fooEnabled;
    }
    public void setFooEnabled(boolean fooEnabled) {
        this.fooEnabled = fooEnabled;
    }
}
Kotlin
class Settings {
    var isFooEnabled: Boolean = false
}

Класс приложения использует этот бин для хранения своих настроек. Помимо основного метода, класс имеет еще два: saveSettings() сохраняет настройки бина в файл с именем settings.xml, а loadSettings() повторно загружает эти настройки. Следующий метод main() создает контекст приложения Spring и вызывает эти два метода:

Java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
public class Application {
    private static final String FILE_NAME = "settings.xml";
    private Settings settings = new Settings();
    private Marshaller marshaller;
    private Unmarshaller unmarshaller;
    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }
    public void setUnmarshaller(Unmarshaller unmarshaller) {
        this.unmarshaller = unmarshaller;
    }
    public void saveSettings() throws IOException {
        try (FileOutputStream os = new FileOutputStream(FILE_NAME)) {
            this.marshaller.marshal(settings, new StreamResult(os));
        }
    }
    public void loadSettings() throws IOException {
        try (FileInputStream is = new FileInputStream(FILE_NAME)) {
            this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
        }
    }
    public static void main(String[] args) throws IOException {
        ApplicationContext appContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Application application = (Application) appContext.getBean("application");
        application.saveSettings();
        application.loadSettings();
    }
}
Kotlin
class Application {
    lateinit var marshaller: Marshaller
    lateinit var unmarshaller: Unmarshaller
    fun saveSettings() {
        FileOutputStream(FILE_NAME).use { outputStream -> marshaller.marshal(settings, StreamResult(outputStream)) }
    }
    fun loadSettings() {
        FileInputStream(FILE_NAME).use { inputStream -> settings = unmarshaller.unmarshal(StreamSource(inputStream)) as Settings }
    }
}
private const val FILE_NAME = "settings.xml"
fun main(args: Array<String>) {
    val appContext = ClassPathXmlApplicationContext("applicationContext.xml")
    val application = appContext.getBean("application") as Application
    application.saveSettings()
    application.loadSettings()
}

Application требует установки свойств для marshaller и unmarshaller. Сделать это можно с помощью следующего файла applicationContext.xml:

<beans>
    <bean id="application" class="Application">
        <property name="marshaller" ref="xstreamMarshaller" />
        <property name="unmarshaller" ref="xstreamMarshaller" />
    </bean>
    <bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
</beans>

В данном контексте приложения используется XStream, но можно было бы использовать любой другой экземпляр машализатора, описанный далее в этой главе. Обратите внимание, что по умолчанию XStream не требует дополнительного конфигурирования, поэтому определение бина довольно простое. Также обратите внимание, что XStreamMarshaller реализует как Marshaller, так и Unmarshaller, поэтому можно ссылаться на бин xstreamMarshaller как в свойстве marshaller, так и в свойстве unmarshaller приложения.

Этот образец приложения порождает следующий файл settings.xml:

<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>

6.4. Пространство имен XML-конфигурации

Можно настроить маршализаторы более лаконично, используя теги из пространства имен OXM. Чтобы эти теги были доступны, для начала нужно сослаться на соответствующую схему в преамбуле конфигурационного XML-файла. В следующем примере показано, как это сделать:

<?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:oxm="http://www.springframework.org/schema/oxm" 
xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/oxm https://www.springframework.org/schema/oxm/spring-oxm.xsd"> 
  1. Ссылаемся на схему oxm.
  2. Задаем местоположение схемы oxm.

Схема дает доступ к следующим элементам:

Разъяснение по каждому тегу приведено в соответствующем разделе, посвященному маршализатору. Как пример, конфигурация маршализатора JAXB2 может выглядеть следующим образом:

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>