В данном уроке будем знакомиться с таким инструментом как JAXB, где он используется и, естественно, рассмотрим все на простых примерах.
Шаг 0. Обзор
JAXB – Java Architecture for XML Binding. Специальный инструмент для маршалинга и анмаршалинга объектов. Часто используется в веб сервисах для представления объекта в виде XML схемы и передачи ее по сети. Также, такой способ передачи данных имеет свой плюс при обмене данных между системами, написанными на разных языках.
Шаг 1. Моделирование задачи
Для того, чтобы проще приставить работу и принцип, предлагаю Вам поставить конкретную задачу, к выполнению которой мы будем идти на протяжении урока.
И так, представьте себе, что у нас есть игра, в которой у нас есть игрок(персона), естественно у него есть такие атрибуты как имя, возраст и друзья.
Условия:
1. Мы не можем использовать базы данных, но при выходе мы должны сохранить все атрибуты нашего объекта.
2. В будущем, мы должны отправить данные на другой сервис, написанный на С++.
3. Возможность сохранить в другом виде(формате)
И так, если смотреть на все просто, то можно:
“Простые” решения:
1. Сохранить в файл атрибуты, считывать их
2. Отправлять отдельно каждый атрибут сущности
3. Создать еще один парсер, со всеми вытекающими
Но, эти, на первый взгляд, “простые” решения содержат в себе подводные камни.
“Но” наших “простых” решений:
1. Нам нужно писать свой парсер чтобы разбирать файл с данными. Тем более, если объект содержит список объектов своего класса. В общем все не очень красиво.
2. В дальнейшем, при отправке на другой сервис, естественно, можно использовать атрибуты и отправлять их отдельно, но, это во первых не очень удобно, во вторых мы создаем свой “стандарт” который также нужно разбирать по своему.
3. Каждый раз все проблемы первого пункта.
В итоге, используя такой подход мы потратим много времени на написание парсеров, настройке, отладке, а также настройке 2 систем. Тем более, что если нам нужно поменять тип сохранения данных в какой-то другой формат(JSON)?
Шаг 2. Создание структуры проекта
Определимся с тем, что и как у нас будет строиться.
entity – здесь размещаем наши сущности. По логике приложения у нас она одна – Person.
parser – здесь разместим классы, которые будут управлять парсингом нашего ентити.
Parser – интерфейс, который содержит в себе 2 метода для сохранения и для восстановления объекта.
Impl – пакет, внутри которого будут классы которые реализуют наш Parser. Таким образом мы можем легко менять парсеры в коде.
Помимо всего, у нас есть класс JaxbParserTest с помощью которого мы будем тестировать работу нашего парсера.
Шаг 3. Создание и аннотирование сущности
Создаем нашу сущность и аннотируем ее для JAXB. Если новая версия JDK выше 1.5, то подключать ее не нужно.
@XmlRootElement(name = "person") @XmlType(propOrder = {"name","age","friends"}) public class Person { private String name; private int age; private List<Person> friends; public String getName() { return name; } @XmlElement public void setName(String name) { this.name = name; } public int getAge() { return age; } @XmlElement public void setAge(int age) { this.age = age; } public List<Person> getFriends() { return friends; } @XmlElement(name = "friend") @XmlElementWrapper public void setFriends(List<Person> friends) { this.friends = friends; } @Override public String toString() { String res = "Person{" + "name='" + name + '\'' + ", age=" + age + ", friends{"; if(friends != null){ for(Person p : friends){ res += p.toString(); } } res += "}}"; return res; } }
@XmlRootElement(name = “person”) – указывает на корневой тег. Имя указывать необязательно.
@XmlType(propOrder = {“name”,”age”,”friends”}) – указываем последовательность атрибутов в XML схеме.
@XmlElement – указывает на элемент который должен находиться в схеме. Можно не указывать, если элемент не должен менять свое имя.
@XmlElementWrapper – используется для коллекций, чтобы создать в схеме поверх них обертку. Таким образом, XML будет выглядеть более читабельно и понятно для человека.
Шаг 4. Создание парсера
В первую очередь, создаем наш интерфейс, от которого мы потом сможем двигаться в разные стороны, сделать приложение гибким.
public interface Parser { Object getObject(File file, Class c) throws JAXBException; void saveObject(File file, Object o) throws JAXBException; }
Теперь создаем реализацию для нашего интерфейса.
public class JaxbParser implements Parser { @Override public Object getObject(File file, Class c) throws JAXBException { JAXBContext context = JAXBContext.newInstance(c); Unmarshaller unmarshaller = context.createUnmarshaller(); Object object = unmarshaller.unmarshal(file); return object; } @Override public void saveObject(File file, Object o) throws JAXBException { JAXBContext context = JAXBContext.newInstance(o.getClass()); Marshaller marshaller = context.createMarshaller(); marshaller.marshal(o,file); } }
JAXBContext().newInstance() – создаем образец контекста и передаем Class объекта с которым будем работать
context.createUnmarshaller() – создаем анмаршаллер :-)
unmarshaller.unmarshall(file) – сохраняем данные схемы в объект. file – файл, с которого читаются данные.
context.createMarshaller() – создаем маршаллер. (запись объекта в файл в виде XML)
marshaller.marshal(o,file) – сохраняем объект o, в файл file.
Шаг 5. Пишем тест для проверки работы парсера
Теперь осталось проверить как работает наш код. Делаем сохранение и вывод восстановленных данных на экран.
public class JaxbParserTest { private Parser parser; private File file; @Before public void setUp() throws Exception { parser = new JaxbParser(); file = new File("person.xml"); } @Test public void testGetObject() throws Exception { Person person = (Person) parser.getObject(file, Person.class); System.out.println(person); } @Test public void testSaveObject() throws Exception { Person person = new Person(); person.setName("Oleg"); person.setAge(19); Person friend1 = new Person(); Person friend2 = new Person(); friend1.setName("Viktor"); friend1.setAge(20); friend2.setName("Stepan"); friend2.setAge(15); List<Person> friends = new ArrayList<Person>(); friends.add(friend1); friends.add(friend2); person.setFriends(friends); parser.saveObject(file,person); } }
Шаг 6. Аннотации
@XmlTransient – помечаются поля, которые не будут включены в маршалинг
@XmlSeeAlso – используется, когда в классе существует объект другого класса
@XmlEnum – для перечислений
@XmlEnumValue – значение для полей в перечислении
@XmlAccessorType – что именно будет сериализовано
@XmlElements – контейнер для нескольких @XmlElement
@XmlMimeType – mime-type для поля
ПОХОЖИЕ ПУБЛИКАЦИИ
- None Found
8 комментариев к статье "JAXB пишем Hello World"