вторник, 19 ноября 2013 г.

Валидация по схеме в Jaxb2Marshaller

Для маршаллинга soap-объектов используем org.springframework.oxm.jaxb.Jaxb2Marshaller - удобный и быстрый.
На этапе отладки взаимодействия между двумя системами решено было использовать и валидацию по xsd-схемам, чтобы эффективнее отлавливать нарушения контракта. Выбранный маршаллер отлично справляется с этой задачей - необходимо указать ему одну или несколько схем, по которым проводить валидацию, и проверка начнётся.


Поскольку для конфигурации нашего приложения используется springframework, то создание маршаллера выглядит так (всё в одном для простоты):
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="contextPaths">
            <array>
                <value>com. ... .message.refunder</value>
            </array>
        </property>
        <property name="schemas">
            <array>
                <!-- в качестве параметра может быть любая из реализаций org.springframework.core.io.Resource -->
                <bean class="org.springframework.core.io.ClassRelativeResourceLoader$ClassRelativeContextResource">
                    <constructor-arg name="path" value="Refunder.xsd"/>
                    <constructor-arg name="clazz" value="com. ... .SoapUtil"/>
                </bean>
            </array>
        </property>
    </bean>
</constructor-arg>
contextPaths - это перечень директорий, в которых размещаются сгенерированные jaxb-объекты (можно задать и конкретные классы или пакеты, например);
schemas - перечень схем для валидации.

Если маршаллер "знает" хотя бы про одну схему, он пытается выполнять валидацию всего, что через него проходит. Если валидация не нужна - свойство schemas устанавливать не нужно.
Всё классно и то, что в данном случае надо!

Ну, и в качестве завершающего штриха захотелось было сделать дополнительную настройку типа "выполнять валидацию или нет" - булев флаг, который можно задавать не в spring-конфигурации, а в текстовом properties-файле. Идея в том, чтобы заранее подготовить перечень xsd-схем. И передавать этот перечень вместе с флагом (а флаг можно получить с помощью placeholder из properties-файла) в прикладной код, который работает с маршаллером. И при значении флага "true" делать вызывать marshaller.setSchemas(перечень схем). В результате не надо лезть в spring-файлы и искать, а где же там настраивается маршаллер. Достаточно в легко доступном текстовом файле изменить флаг. Например, это удобно коллегам из отдела внедрения и сопровождения.
Но не тут-то было. После реализации идеи маршаллер напрочь "забыл" о том, что надо проводить валидацию.
При осмотре кода самого маршаллера выяснилось, что задать-то перечень схем для проверки можно в любой момент времени с помощью того же метода:
public void setSchemas(Resource[] schemaResources)
Но - реальная загрузка схем из перечня выполняется только один раз, при создании бина и где-то в недрах самого springframework.
В деталях - маршаллер реализует интерфейс org.springframework.beans.factory.InitializingBean и его метод void afterPropertiesSet(); он вызывается после установки свойств бина, и к моменту получения объекта в прикладном коде оказывается уже выполненным. И вот в нём-то и выполняется private Schema loadSchema(...)! А поскольку последний закрыт для доступа, но и вызвать его в прикладном коде для перезагрузки схем не выходит. Грустно :(, придётся писать ещё немного кода и создавать экземпляр маршаллера самостоятельно.

Комментариев нет:

Отправить комментарий