 | Уровень сложности: сложный Бретт МакЛафлин, автор и редактор, O'Reilly Media, Inc.
10.11.2008 Прочитав первые две статьи серии, вы уже должны уметь использовать Castor для преобразования Java™-объектов в XML и обратно. В данной статье мы расскажем, как с помощью файлов отображения можно добавить гибкости в этот процесс. Вам больше не придется мириться с ограничениями, накладываемыми именами элементов в документах XML, или названиями переменных в Java-классах.
Что вы должны помнить из предыдущих статей
Как и в предыдущей части, в основе этой статьи лежат определенные предположения относительно того, что установлено на вашем компьютере и что вы уже знаете и умеете. Во-первых, после прочтения первой статьи у вас должна быть загружена, установлена и настроена последняя версия Castor. Это означает, что корректно настроены пути к файлам классов, включая все необходимые для работы Castor библиотеки (ссылка на первую статью серии приведена в разделе Ресурсы). Далее, прочитав вторую часть серии, вы должны свободно владеть базовыми функциями Castor для работы с маршаллингом и демаршаллингом.
Это означает, что вы можете взять документ XML, извлечь из него данные с помощью Castor и далее работать с ними, используя ваши собственные Java-классы. В терминологии связывания с данными (data binding) это называется демаршаллингом. То же самое справедливо и для маршаллинга: вы должны уметь преобразовывать данные, хранящиеся в переменных экземпляров ваших Java-классов, в документ XML. Если у вас возникают трудности с программным использованием маршаллинга и демаршаллинга в Castor, то обратитесь ко второй статье серии (ссылка на нее также приведена в разделе Ресурсы).
Связывание с данными в неидеальном мире
На первый взгляд может показаться, что вы уже знаете все, что необходимо для эффективного использования Castor: установку и конфигурирование, маршаллинг и демаршаллинг. Однако все, о чем рассказывалось выше, работает только в так называемом “идеальном мире”. В этом мире все создают идеальные документы XML с осмысленными именами элементов, например, "title" и "authorAddress" вместо "t" or "aa". Java-классы так же хорошо организованы, их имена представляют собой существительные в единственном числе, например, “Book”. Аналогичным образом имена присваиваются переменным-членам классов, например, "isbn" и "price". Кроме того, не существует некорректных типов данных: в частности, ни один из разработчиков не использует int вместо float для переменной price или же массив char для строкового значения, считая, что он все еще пишет код на С.
Однако большинство программистов живут далеко не в идеальном мире (я все еще нахожусь в поисках того волшебного гардероба, который открывает дверь в этот мир). В мире, в котором большинство программистов получают зарплату и платят ипотеку, документы XML зачастую содержат ужасные имена элементов и атрибутов, не говоря уже о множестве проблем, связанных с пространствами имен. Данные, предназначенные для хранения в элементах, содержатся в значениях атрибутов, а некоторые данные разделяются конвейерными символами или точками с запятой.
Java-классы часто бывают унаследованными, а переписывать их как правило нецелесообразно ввиду слишком больших затрат, в том числе временных. Классы как правило плохо отображаются на XML-схему (сама мысль о том, что программисты Java и люди, работающие с данными в XML, смогут найти общий язык, кажется нереальной). Иногда, конечно, существует четкое соответствие между Java-классами и XML-схемой, но точно не для всех классов и данных. Имена переменных-членов классов часто бывают такими же неудачными, как и имена элементов в XML. Вам приходилось читать код программиста, использующего Венгерскую нотацию, в которой все имена переменных начинаются с "m", например, mTitle? Не очень-то приятное зрелище.
Используя методы, о которых рассказывалось до этого момента, вам не удастся продвинуться особенно далеко в реальном мире. В лучшем случае у вас получатся отвратительные документы XML с “венгерскими” именами элементов или уродливые Java-классы, структура которых лишена всякого смысла. Так жить нельзя. В конце концов, какая польза от Castor (или от любой другой инфраструктуры для связывания с данными), если нельзя взять данные XML-документы и манипулировать ими произвольным образом?
Цели гибкого связывания с данными
Прежде всего учтите, что использование файлов отображения (в Castor или в любой другой инфраструктуре для связывания с данными) требует навыков, изучение которых занимает определенное время. Во-первых, придется выучить новый синтаксис. Даже если в файлах отображения используется XML, а в большинстве библиотек так и есть, вам все равно придется разбираться с новыми именами элементов и атрибутов. Далее будьте готовы к тому, что понадобится более тщательное тестирование, чтобы убедиться, что преобразование из Java в XML и обратно происходит именно так, как вы задумали. Наконец, учтите, что будут чаще случаться всевозможные ошибки при связывании с данными, потому что теперь вы сами, а не инфраструктура, управляете отображением. Например, если вы указываете, что элемент fiddler в XML должен отображаться на переменную violin в Java, но в классе player вместо Player – произойдет ошибка. Внезапно все мелкие детали, связанные с написанием имен, регистром букв, подчеркиванием, двойными и одинарными кавычками, начинают играть очень существенную роль.
У вас должны быть достаточно веские основания для того чтобы углубиться во все эти нюансы. Изучение файлов отображения только для того чтобы гордо заявлять, что вы их знаете – это пустая трата времени. Тем не менее их использование дает некоторые серьезные преимущества.
Документы XML не накладывают ограничений на Java-код
Я уже упомянул о том, как регистр символов может служить источником неприятностей при преобразовании из XML в Java. Наиболее часто используемым подходом к именованию элементов в XML является использование названий в нижнем регистре с дефисами, таких как first-name. Иногда даже можно встретить first_name. В обоих случаях при стандартном отображении пришлось бы использовать уродливые имена переменных в Java, но никто не захочет видеть методы с названием getFirst-name() у себя в коде. По правде говоря, большинство документов, использующих “верблюжью” (camel-case) нотацию для именования элементов и атрибутов, например, firstName, были созданы программистами, а не разработчиками XML или специалистами по работе с данными. При использовании файлов отображения соответствие между именами в стиле XML, например, first-name, и именами в стиле Javа, такими как firstName, устанавливается тривиально. А самое главное преимущество заключается в том, что вам не придется заставлять своих XML-специалистов думать в стиле программистов Java, что зачастую гораздо сложнее, чем выучить новый синтаксис для отображения.
Имена в Java не накладывают ограничений на документы XML
Это звучит как нечто само собой разумеющееся. Если можно управлять преобразованием имен из XML в Java, то аналогичным образом можно менять имена в Java при переносе данных из классов в документы XML. Но существует еще более важное, хотя и менее очевидное преимущество: вам больше не придется чувствовать ограничения, накладываемые именами и названиями пакетов Java-классов.
В целом это становится просто вопросом организации. Представьте, что в большинстве случаев вложенные элементы в XML представляют собой сами классы, а самые нижние элементы являются их свойствами (переменными-членами классов). Например, как в документе XML, приведенном в листинге 1.
Листинг 1. Представление книги в XML
<?xml version="1.0" encoding="UTF-8"?>
<book>
<authors total-sales="0">
<last-name>Finder</last-name>
<first-name>Joseph</first-name>
</authors>
<isbn>9780312347482</isbn>
<title>Power Play</title>
</book>
|
Castor (как и любая другая инфраструктура для связывания с данными) скорее всего предположит, что Book должен быть классом, содержащим ссылки на экземпляры класса Author. Последний должен содержать переменные-члены lastName и firstName (уже на этом этапе мы сталкиваемся с проблемами именования: должна переменная называться last-name или lastName? Аналогичный вопрос встает и в случае firstName). А если это не то, что вы хотите? Предположим, что вы храните всех авторов, докладчиков на конференциях и профессоров в одном общем классе под названием Person или Professional. Это представляет собой реальную проблему, но для ее решения вам не придется полностью реструктурировать XML-документ, изменив имена всех элементов. На самом деле это тот случай, когда отображение является единственным способом сохранить документ XML в первоначальном виде, не меняя его в соответствии с архитектурными решениями, сделанными программистами Java.
Отображение предоставляет возможность контролировать принципы именования на обеих сторонах преобразования Java-XML. Точно так же, как вы не хотите менять Java-код в соответствии с пожеланиями авторов документов XML, вы не должны изменять структуру XML, чтобы она соответствовала организации классов Java и их переменных-членов. И добавьте сюда еще названия пакетов в Java. Несмотря на то что в Castor они представляют собой меньшую проблему, вам все же придется сохранить информацию об именах классов и пакетов в сгенерированном документе XML, что плохо с точки зрения отделения бизнес-логики (Java-классов) от данных (XML). Все эти проблемы можно решить с помощью отображения.
Отображение позволяет добавить связывание с данными в ранее созданные приложения
Обе описанные выше проблемы (ограничения, накладываемые Java-классами и структурой XML-документов) на самом деле являются разными сторонами более масштабной проблемы. В большинстве случаев у вас уже есть набор объектов Java, а также один или несколько документов XML. Поэтому вам недоступна гибкость, продемонстрированная в предыдущих статьях, в которых вы могли позволить Castor решать, в какого вида XML преобразовывать ваши Java-объекты, или создавать Java-классы специально под существующий XML-документ.
Теперь вы находитесь в гораздо более реальной ситуации, когда нужно добавить новую технологию – связывание с данными – в существующую структуру. В этом случае отображение может стать тем фактором, от которого зависит, использовать связывание с данными или нет. Благодаря ему вы можете оставить нетронутыми два полюса вашей системы – объектную модель и структуру XML, и тем не менее наладить обмен данными между ними. Другими словами, хорошо спроектированная система отображения делает связывание с данными полезным в реальном мире, а не только в качестве теоретического упражнения.
Простой сценарий отображения
Для начала создадим простой сценарий отображения, который далее можно будет использовать в качестве примера. В предыдущей статье мы создали классы Book и Author. Они приведены ниже (в листинге 2 показан класс Book).
Листинг 2. Класс Book
package ibm.xml.castor;
import java.util.LinkedList;
import java.util.List;
public class Book {
/** ISBN книги */
private String isbn;
/** Название книги */
private String title;
/** Имена авторов */
private List<Author> authors;
public Book() { }
public Book(String isbn, String title, List<Author> authors) {
this.isbn = isbn;
this.title = title;
this.authors = authors;
}
public Book(String isbn, String title, Author author) {
this.isbn = isbn;
this.title = title;
this.authors = new LinkedList<Author>();
authors.add(author);
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getIsbn() {
return isbn;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setAuthors(List<Author> authors) {
this.authors = authors;
}
public List<Author> getAuthors() {
return authors;
}
public void addAuthor(Author author) {
authors.add(author);
}
} |
В листинге 3 приведен класс Author.
Листинг 3. Класс Author
package ibm.xml.castor;
public class Author {
private String firstName, lastName;
public Author() { }
public Author(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
} |
Замечание: Единственным изменением по сравнению с предыдущей статьей стало то, что я убрал переменную totalSales, так как в ней и ранее не было особой необходимости.
Проблемный документ XML
Вместо XML-документа из предыдущей статьи мы возьмем другой, который не будет столь хорошо соответствовать структуре классов Java. В листинге 4 приведен документ, с которым необходимо связать классы, показанные в листингах 2 и 3.
Листинг 4. Документ XML, содержащий данные для связывания
<?xml version="1.0" encoding="UTF-8"?>
<book>
<author>
<name first="Douglas" last="Preston" />
</author>
<author>
<name first="Lincoln" last="Child" />
</author>
<book-info>
<isbn>9780446618502</isbn>
<title>The Book of the Dead</title>
</book-info>
</book>
|
Что должно отображаться?
Прежде чем думать о семантике файла отображения, API Castor или о чем-либо другом, вы должны выяснить, что необходимо сделать, чтобы представить XML-данные в листинге 4 в виде объектов Java-классов, приведенных в листингах 2 и 3. Подумайте об этом некоторое время.
Вот краткое описание того, как XML должен отображаться на структуру классов Java:
- Элемент
book должен отображаться в виде экземпляра класса Book.
- Каждый элемент
author должен отображаться в виде экземпляра класса Author.
- Каждый экземпляр
Author должен быть добавлен в список authors экземпляра класса Book.
- В каждом экземпляре класса
Author переменная firstName должна хранить значение, содержащееся в атрибуте first элемента name.
- В каждом экземпляре класса
Author переменная lastName должна хранить значение, содержащееся в атрибуте last элемента name.
- Переменная
isbn экземпляров класса Book должна хранить значение элемента isbn, вложенного внутрь элемента book-info.
- Переменная
title экземпляров класса Book должна хранить значение элемента title, вложенного внутрь элемента book-info.
Вы уже знаете, как сделать некоторые из этих вещей. Например, элемент book отображается на экземпляр класса Book стандартным образом, и Castor сделает это по умолчанию. Но существуют и некоторые шероховатости, например, в случае с авторами. В то время как элемент author достаточно неплохо отображается на структуру класса Author, в XML не существует группирующего элемента аналогичного authors, который бы подчеркнул, что каждый автор являются частью единого списка, относящегося к экземпляру класса Book.
Кроме того, есть места, в которых элементы и атрибуты напрямую не отображаются на объектную модель в Java. В частности, класс Author содержит переменные для раздельного хранения имени и фамилии, в то время как в XML используется единый элемент name с двумя атрибутами. Вдобавок названия и коды ISBN книг вложены внутрь элемента book-info, который не отображается ни на один объект в Java.
Отображение – это то, что нужно в данной ситуации. С его помощью можно взять этот документ XML, который содержит нужные, но произвольно структурированные данные, и перенести их в экземпляры ваших Java-классов. И, как вы вскоре убедитесь, создание файла отображения не представляет собой серьезных трудностей.
Основы файлов отображения
Отображение в Castor реализуется с помощью специальных файлов (называемых файлами отображения), которые представляют собой обычные XML-документы, содержащие информацию о том, как преобразовывать данные из Java в XML и обратно. Так как вы уже знакомы с XML, создание файлов отображения не покажется вам чем-то трудным. В несложных случаях, когда необходимо просто установить соответствие между различными именами элементов XML и переменных в Java, создание файла отображения занимает считанные секунды.
Этот файл используется внутри Castor в процессе маршаллинга и демаршаллинга – то, с чем вы уже умеете работать через программные интерфейсы, прочитав две последние статьи. Теперь вам понадобится всего один дополнительный вызов API Castor – все остальное останется без изменений.
Элемент mapping
Файлы отображения в Castor представляют собой старые добрые документы XML, корневыми элементами которых являютя элементы mapping. Вам также понадобится ссылка на DTD, описывающий структуру документа. С помощью DTD вы сможете проверить корректность вашего документа, избежав вероятных проблем с его синтаксисом или структурой. Это значительно упростит вашу жизнь в случае, если придется отлаживать ваш файл отображения.
Простейший файл отображения показан в листинге 5.
Листинг 5. Пример простейшего файла отображения в Castor
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<!-- Отображение полностью описывается в этой секции -->
</mapping>
|
Очевидно, что этот файл не устанавливает никакого соответствия между структурами Java и XML, но его можно будет использовать в качестве заготовки для будущих файлов.
Отображение классов с помощью элемента class
Следующим шагом после создания заготовки практически всегда является описание отображения классов Java на элементы XML. В нашем примере необходимо связать класс Book с данными, хранящимися в элементе book. Первичными сущностями в файле отображения являются классы, поэтому вам надо сначала добавить элемент class, а затем задать полное имя Java-класса в атрибуте name данного элемента. Пример приведен ниже.
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
</class>
</mapping>
|
Теперь можно задать имя элемента XML, на который отображается данный класс, с помощью элемента map-to и его атрибута xml. Данный элемент является вложенным по отношению к элементу class, который содержит полностью квалифицированное имя отображаемого Java-класса (см. пример ниже).
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
<map-to xml="book" />
</class>
</mapping>
|
Пока все очень просто. До этого момента файл не описывал ничего, что Castor не сделал бы по умолчанию. Вы могли бы вообще пропустить эту часть файла, если бы не две причины:
- Необходимо указать, как конкретные поля в классе
Book, например, title и ISBN, должны заполняться данными.
- Если вам приходится описывать отображение, то лучше, если оно будет полным, т.е. указывать, как связываются все классы, поля и элементы. Тогда файл будет играть роль своего рода документации, четко описывая взаимодействие Java-кода и XML-документов.
Отображение полей на элементы XML
Описав базовое отображение классов на элементы, можно начинать связывать поля класса book с конкретными элементами внутри документа XML. В файлах отображения Castor элемент field используется для указания имени переменной-члена класса Java, а вложенный элемент bind-xml – для указания элемента в XML, на который данная переменная отображается. Ниже показано, как связать переменную title класса Book с XML-элементом title, вложенным внутрь элемента book.
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
<map-to xml="book" />
<field name="Title" type="java.lang.String">
<bind-xml name="title" node="element" />
</field>
</class>
</mapping>
|
 |
Имена свойств защищают ваш код
Основным преимуществом использования имен свойств, которые затем транслируются в названия методов, в том, что они скрывают внутреннюю информацию ваших классов. Если класс содержит метод setTitle(), то Castor может использовать простое имя свойства Title вне зависимости от того, как называется переменная-член класса: title, book-title, mTitle, _title или как-то еще. Таким образом, работа с классом происходит только через открытый API (get- и set-методы), что позволяет сочетать различные стили кодирования.
|
|
Обратите внимание на несколько моментов. Во-первых, задается имя свойства (в данном случае “Title”). Это имя именно свойства, а не переменной. Другими словами, Castor будет использовать это имя, вызывая set-метод set[ИмяСвойства](). Если вы зададите “foo” в качестве имени свойства, то Castor попытается вызвать метод setfoo(), а это, скорее всего, не то, что вам надо. Поэтому следите за регистром символов, и всегда используйте имена свойств ваших Java-классов, а не переменных.
Во-вторых, обратите внимание на использование атрибута type. С его помощью вы указываете Castor какого типа данные могут храниться в этом свойстве. В нашем случае все просто. Но этот атрибут становится жизненно важным, если вы хотите, чтобы числа, хранящиеся в XML в текстовом виде, сохранялись в Java в виде натуральных или десятичных чисел или даже простых строк. В этом случае необходимо использовать полное имя Java-класса, задающее необходимый тип данных (в данном случае java.lang.String).
В элементе bind-xml задается имя элемента XML, на который отображается данное свойство (в нашем случае – “title”). Также необходимо указать, происходит связывание с элементом или атрибутом, используя специальный атрибут node. Таким образом, можно легко получать доступ к значениям как элементов, так и атрибутов, что является еще одной демонстрацией гибкости, обеспечиваемой файлами отображения.
Указание местонахождения элемента XML
Здесь мы сталкиваемся с первой проблемой: элементы, хранящие название книги и ISBN, не расположены непосредственно внутри элемента book, а вложены внутрь элемента book-info. Поэтому необходимо предпринять дополнительные усилия, чтобы отображение работало как следует.
В случаях, когда необходимо связать класс или поле с данными, размещенными не непосредственно внутри XML-элемента, на который отображается данный класс, нужно использовать атрибут location элемента bind-xml. В нем указывается имя элемента в XML, который содержит необходимые данные. Если вы связываете класс или поле с данными некоего элемента, то значением location должно быть имя элемента, являющегося родительским по отношению к данному. Если же связывание происходит с атрибутом, то в location указывается имя элемента, содержащего данный атрибут.
В нашем случае необходимо связать свойство Title класса Book со значением элемента title, вложенного внутрь элемента book-info. Это делается следующим образом:
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
<map-to xml="book" />
<field name="Title" type="java.lang.String">
<bind-xml name="title" node="element" location="book-info"
</field>
</class>
</mapping>
|
Далее добавить отображение поля для ISBN-кода книги не представляет никакой сложности:
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
<map-to xml="book" />
<field name="Title" type="java.lang.String">
<bind-xml name="title" node="element" location="book-info" />
</field>
<field name="Isbn" type="java.lang.String">
<bind-xml name="isbn" node="element" location="book-info" />
</field>
</class>
</mapping>
|
Таким образом, мы связали все свойства класса Book с данными в XML. Пора переходить к классу Author.
Отображение дополнительных классов
Отображение дополнительных классов описывается аналогично отображению основного класса. Единственным отличием является то, что в этом случае вам не придется использовать элемент map-to.
Отображение класса Author
У нас есть все, что нужно для связывания полей класса Author с данными, хранящимися в элементе author. Помните, что вы работаете со следующим фрагментом XML:
<author>
<name first="Lincoln" last="Child" />
</author> |
Единственным неудобством является то, что вместо элементов, хранящих имя и фамилию автора, присутствует один элемент, содержащий два атрибута. В этом случае вы можете вновь использовать атрибут location, в котором можно задать, что необходимые данные содержатся в дочернем элементе name. Кроме того, в атрибуте node необходимо указать, что данные, с которыми происходит связывание, хранятся в атрибуте, а не в элементе. Пример приведен ниже.
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
<map-to xml="book" />
<field name="Title" type="java.lang.String">
<bind-xml name="title" node="element" location="book-info" />
</field>
<field name="Isbn" type="java.lang.String">
<bind-xml name="isbn" node="element" location="book-info" />
</field>
</class>
<class name="ibm.xml.castor.Author">
<field name="FirstName" type="java.lang.String">
<bind-xml name="first" node="attribute" location="name" />
</field>
<field name="LastName" type="java.lang.String">
<bind-xml name="last" node="attribute" location="name" />
</field>
</class>
</mapping>
|
На данный момент отображение должно выглядеть достаточно просто. Мы указали класс, который связывается с данными - Author – и отображаемые свойства, которые содержатся в данном классе - FirstName и LastName. Для каждого свойства мы задали элемент, с которым оно связывается, в данном случае name, а также то, что сами данные находятся в атрибуте.
Связывание классов Book и Author
Если вы внимательнее посмотрите на XML, приведенный выше, вы заметите, что мы нигде не указали, на какой элемент XML должен отображаться класс Author. Это представляет собой проблему, так как сам Castor не будет делать никаких предположений. Поэтому если вы создаете файл отображения, то лучше описывать все детали отображения полностью.
Если бы все наши книги содержали только одного автора, то, скорее всего, в классе Book было бы свойство Author. Тогда можно было бы добавить следующий фрагмент XML в файл отображения:
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
<map-to xml="book" />
<field name="Title" type="java.lang.String">
<bind-xml name="title" node="element" location="book-info" />
</field>
<field name="Isbn" type="java.lang.String">
<bind-xml name="isbn" node="element" location="book-info" />
</field>
<field name="Author" type="ibm.xml.castor.Author">
<bind-xml name="author" />
</field>
</class>
<class name="ibm.xml.castor.Author">
<field name="FirstName" type="java.lang.String">
<bind-xml name="first" node="attribute" location="name" />
</field>
<field name="LastName" type="java.lang.String">
<bind-xml name="last" node="attribute" location="name" />
</field>
</class>
</mapping>
|
В таком случае мы просто добавляем отображение авторов в секцию, описывающую отображение книг, потому что происходит связывание свойства класса Book. Типом отображения является ibm.xml.castor.Author, который связывается с XML-элементом author. При этом Castor будет использовать определение класса Author внутри соответствующего элемента class для отображения всех его свойств.
Очевидно, что проблемой является отсутствие единого свойства Author в классе Book. Вместо этого присутствует свойство Authors, являющееся массивом экземпляров класса Author. Поэтому необходимо указать Castor, что каждый элемент author нужно преобразовать в отдельный объект класса Author (отображение которого мы практически описали), а затем сохранить все подобные объекты в свойстве Authors класса Book.
Отображение элементов на коллекцию
В подобных случаях необходимо преобразовать несколько элементов документа XML, в частности, author, в коллекцию, а затем сохранить ее в свойстве Authors класса Book.
Начнем с элемента field, потому что мы описываем не что иное, как отображение поля класса Book. Так же можно задать “Authors” в качестве значения атрибута name, так как именно это свойство класса Book будет связываться с данными в XML:
<field name="Authors">
</field>
|
Далее необходимо задать тип свойства. На первый взгляд может показаться, что им должен быть класс коллекции. Но на самом деле необходимо указать тип каждого элемента в коллекции (чуть позже я расскажу, как указать то, что это коллекция). Таким образом, значением типа должно быть ibm.xml.castor.Author. Экземпляры именно этого класса Castor должен поместить в свойство Authors:
<field name="Authors" type="ibm.xml.castor.Author">
</field> |
Теперь обратите внимание на ключевой момент: с помощью атрибута collection указывается, что значением этого свойства является коллекция. Значением данного атрибута является тип коллекции. На данный момент Castor поддерживает только два возможных значения: vector для списочных типов и array для массивов. К коллекциям первого типа доступ происходит через стандартный интерфейс Java Collection (методы типа next()), а вторые интерпретируются как массивы в Java, элементы которых доступны через индексы, например, ar[2]. В нашем случае надо использовать vector, потому что типом нашей коллекции является List:
<field name="Authors" type="ibm.xml.castor.Author" collection="vector">
</field> |
Увидев атрибут collection, Castor понимает, что необходимо создать коллекцию, элементами которой будет объекты типа, указанного в атрибуте type. Таким образом, значением свойства Authors должна быть коллекция объектов типа ibm.xml.castor.Author.
Все что осталось – это указать источник данных для экземпляров Author. Это делается с помощью знакомого элемента bind-xml:
<field name="Authors" type="ibm.xml.castor.Author" collection="vector">
<bind-xml name="author" />
</field> |
Вот и все: в итоге у нас получился законченный файл отображения. Он должен выглядеть подобно приведенному в листинге 6.
Листинг 6. Полная версия файла отображения
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.xml.castor.Book">
<map-to xml="book" />
<field name="Title" type="java.lang.String">
<bind-xml name="title" node="element" location="book-info" />
</field>
<field name="Isbn" type="java.lang.String">
<bind-xml name="isbn" node="element" location="book-info" />
</field>
<field name="Authors" type="ibm.xml.castor.Author" collection="vector">
<bind-xml name="author" />
</field>
</class>
<class name="ibm.xml.castor.Author">
<field name="FirstName" type="java.lang.String">
<bind-xml name="first" node="attribute" location="name" />
</field>
<field name="LastName" type="java.lang.String">
<bind-xml name="last" node="attribute" location="name" />
</field>
</class>
</mapping>
|
Программное использование файлов отображения
Единственным нерассмотренным аспектом является использование файла отображения при демаршаллинге. Ранее мы использовали класс Unmarshaller статическим образом, вызывая метод Unmarshaller.unmarshal() для преобразования из XML в Java. Теперь, когда у нас есть файл отображения, необходимо создать и настроить экземпляр класса Unmarshaller. В листинге 7 приведен класс, который управляет демаршаллингом документа XML в объекты Java.
Листинг 7. Демаршаллинг с использованием файла отображения
package ibm.xml.castor;
import java.io.FileReader;
import java.util.Iterator;
import java.util.List;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Unmarshaller;
public class BookMapUnmarshaller {
public static void main(String[] args) {
Mapping mapping = new Mapping();
try {
mapping.loadMapping("book-mapping.xml");
FileReader reader = new FileReader("book.xml");
Unmarshaller unmarshaller = new Unmarshaller(Book.class);
unmarshaller.setMapping(mapping);
Book book = (Book)unmarshaller.unmarshal(reader);
System.out.println("Book ISBN: " + book.getIsbn());
System.out.println("Book Title: " + book.getTitle());
List authors = book.getAuthors();
for (Iterator i = authors.iterator(); i.hasNext(); ) {
Author author = (Author)i.next();
System.out.println("Author: " + author.getFirstName() + " " +
author.getLastName());
}
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace(System.err);
}
}
} |
Изменения по сравнению с демаршаллингом, который описывался в предыдущих статьях, минимальны. Во-первых, создается экземпляр класса Unmarshaller, которому передается Book.class в качестве аргумента. Таким образом, задается имя класса верхнего уровня для демаршаллинга. Обратите внимание, что этот класс верхнего уровня должен соответствовать XML-элементу mapping, включающему элемент map-to. Далее устанавливается отображение и, наконец, вызывается нестатический метод unmarshal().
И на этом все! Нет ничего принципиального нового по сравнению с тем, что было продемонстрировано ранее. В принципе, почему бы вам в качестве упражнения не попробовать написать код для маршаллинга Java-объектов в XML? Используйте класс BookMarshaller из последней статьи в качестве примера, внесите необходимые изменения в файл отображения, и вы сможете сделать преобразование из Java в XML и обратно, не затратив большого количества времени.
Заключение
Главное в связывании с данными – это сами данные, а не формат, в котором они хранятся. Работать с объектами Java достаточно просто для большинства программистов Java, а связывание с данными аналогично упрощает их получение из различных источников, в частности, XML, и преобразование в объекты. Отображение представляет собой следующий шаг – оно придает необходимую гибкость процессу наполнения объектов данными, позволяя работать с различными форматами данных. Так что если вас привлекает связывание с данными, то вы полюбите отображение. С его помощью вы сможете связывать объекты с документами XML, структура которых не отвечает вашим правилам именования или же не соответствует структуре ваших Java-объектов.
То же самое справедливо и для тех из вас, кто занимается работой с данными. Вы сможете получать нужные данные из классов Java не создавая промежуточные слои для хранения значений методов в странных элементах XML. Вам не придется создавать документы XML, в которых несколько элементов соответствуют одному классу Java. Основной акцент делается на гибкость и возможность работать с данными так, как вы считаете нужным вместо того чтобы следовать ограничениям, накладываемым некой инфраструктурой или технологией.
Что дальше?
Вы узнали, что нового приносит Castor в мир XML. Но это всего лишь малая часть возможностей его API. В следующей статье мы перейдем от простого связывания с данными к возможностям Castor по связыванию с данными SQL. Вы узнаете, как быстро переносить информацию из классов Java в базу данных SQL и обратно без использования JDBC. Поэтому продолжайте знакомиться с XML, освежите свои знания SQL и через месяц будьте готовы изучать еще более мощные возможности по связыванию с данными.
К тому времени как вы прочитаете следующую статью (последнюю в данной серии), вы сможете свободно переносить данные между XML, Java и базами данных SQL, и все это – используя единый API. Это представляет собой еще большую гибкость, чем файлы отображения. С помощью единого API и схожих вызовов для всех форматов хранения данных вы сможете работать с базами данных, объектами Java и документами XML. Те из вас, кто периодически заглядывает в мир С#, могут уловить сходство с LINQ – новейшей и одной из самых раскрученных технологий в Visual C# 2008. И все это доступно прямо сейчас в виде стабильного API в Java. Неплохо, не так ли? Так что смелее вперед, реализуйте связывание с данными и смотрите, что получится. Получайте удовольствие, и встретимся в сети.
Загрузка | Описание | Имя | Размер | Метод загрузки |
|---|
| Примеры кода к статье | x-xjavacastor3-Code.zip | 46КБ | HTTP |
|---|
Ресурсы Научиться
- Оригинал статьи: "Data binding with Castor, Part 3: Map between schemas". (EN)
- Прочитав первую статью "Data binding with Castor, Part 1: Install and set up Castor" (Брэт Маклафлин, developerWorks, ноябрь 2007 г.), вы сможете загрузить, установить и настроить Castor на вашем компьютере.
- В статье "Связывание с данными с помощью Castor, часть 2: Маршаллинг и демаршаллинг в XML" (Бретт Маклафлин, developerWorks, декабрь 2007 г.) рассказывается о преобразовании Java-объектов к XML-представлению и их обратном восстановлении из XML. Статья также рассказывает о принципах работы Castor и о том, как создавать классы, совместимые с Castor API. (EN)
- Узнайте, как превратить набор Java-объектов в строки в базе данных SQL, прочитав статью "Связывание с данными с помощью Castor, часть 4: Связывание Java-объектов с базами данных SQL" (Брэт Маклафлин, developerWorks, апрель 2008 г.). Вы сможете добавить базы данных SQL к списку источников данных, с которыми вы уже умеете осуществлять связывание. В статье будет показано, чем связывание с SQL отличает от XML. (EN)
- Посетите Web-сайт Castor, в котором собраны все необходимые материалы. (EN)
- Обратитесь к Java-документации по классам Castor. (EN)
- Если вы только начинаете изучать XML, посетите сайт xml.com, содержащий множество материалов по XML для начинающих. (EN)
- Прочитайте достаточно давно написанную статью под названием "Поддержка JDO в Castor" (Брюс Снайдер (Bruce Snyder), developerWorks, август 2002 г.). Некоторые конструкции языка, описанные в статье, устарели, но общие идеи по-прежнему актуальны. (EN)
- Ознакомьтесь со статьей "Связывание с данными на практике" (Бретт Маклафлин, developerWorks, май 2004 г.), являющейся вводной в серии, посвященной JAXB – API для связывания с данными от Sun. (EN)
-
Сертификация по XML корпорации IBM: узнайте, как стать сертифицированным разработчиком IBM в области XML и связанных с ним технологий. (EN)
- Обратитесь к технической библиотеке XML, содержащей множество статей, советов, руководств, стандартов и справочников IBM Redbooks. (EN)
-
Технические мероприятия и Web-трансляции developerWorks: в этих разделах можно получить самую актуальную информацию о современных технологиях. (EN)
- Обратитесь к магазину технической литературы, в котором представлены книги на данную и другие темы. (EN)
Получить продукты и технологии
- Книга "Java и XML, 3-е издание" (Бретт Маклафлин и Джастин Эдельсон (Justin Edelson), O'Reilly Media, Inc.) описывает все аспекты XML, сначала и до конца, включая вопросы связывания с данными и отображения. (EN)
- В более ранней книге "Java и связывание с XML-данными" (Бретт Маклафлин, O'Reilly Media, Inc.) приводится информация о Castor и общих принципах связывания с данными. (EN)
- Если вы хотели бы получить платную поддержку Castor, то ознакомьтесь со списком коммерческих услуг. (EN)
- Скачайте ознакомительные версии программного обеспечения IBM: используйте в вашем следующем проекте ознакомительные версии ПО, которые можно скачать прямо с сайта IBM developerWorks. (EN)
Обсудить
Об авторе  | |  | Бретт МакЛафлин (Brett McLaughlin) работает с компьютерами со времен Logo (помните маленький треугольник?). За последние несколько лет он стал одним из наиболее известных авторов и программистов сообщества по технологиям Java и XML. Он работал в Nextel Communications над реализацией сложных корпоративных систем, в Lutris Technologies - фактически над созданием серверов приложений, - а с недавнего времени - в O'Reilly Media, Inc., где продолжает писать и редактировать важные и содержательные книги. Его готовящаяся книга "Head Rush Ajax" продолжает отмеченный наградами инновационный подход "Вперед головой" применительно к изучению Ajax. Его недавняя книга Java 1.5 Tiger: Заметки разработчика является первой доступной книгой по новейшей версии технологии Java, а его классическая книга Java и XML остается одной из наиболее авторитетных работ по применению технологий XML в языке Java. |
Выскажите мнение об этой странице
|  |