Я помню, что в конце 90-х / начале 2000-х все программирование было связано с XML. Все «эксперты» сказали, что вы должны использовать XML для обмена данными. У XML есть много преимуществ. Но часто при сегодняшнем программировании XML выглядит как «старая школа» или слишком ограничительный. XML наверняка может быть привередливым в работе. Многие разработчики, когда им предоставляется выбор (включая меня), будут использовать JSON поверх XML. JSON гораздо более простителен, чем XML, что упрощает работу с ним.
Хотя XML может быть старой школой, его все же можно использовать. Даже когда вы делаете основанные на JSON веб-службы Restful.
Веб-сервисы Restful весной
Я не собираюсь рассказывать о создании Restful Web Services в Spring в этом посте. Это тема будущего. Но когда вы используете Spring MVC для разработки Restful Web Services, вы можете настроить большую гибкость. Обычно я разрабатываю свои веб-сервисы, чтобы клиент мог использовать JSON или XML. Стандарты поддерживают это, и это довольно легко сделать.
Многие из примеров, которые вы увидите в Интернете, начнутся с использования аннотированных JAXB Java POJO. Это работает, но я также чувствую, что это ошибка. Контракт для ваших веб-сервисов теперь является классом Java. Который может работать для вас, но это не переносимо. Что если один из ваших клиентов пишет на PHP? JAXB-аннотированный Java-класс для них бесполезен.
XML-схема
Схема XML — это спецификация для описания документов XML. Думайте об этом как о строгой типизации для XML-документа. Вы можете указать свойства, если они могут быть нулевыми, их типы данных, если они могут быть списком и т. Д. Возможности схемы XML очень надежны.
Отличная особенность JAXB — вы можете генерировать аннотированные JAXB Java POJO из документа XML-схемы. И когда вы делаете это, у вас теперь есть переносной контракт на типы данных ваших веб-сервисов. Ваш «контракт» больше не привязан к языку программирования Java. Вы можете передать XML-схему кому-то, строящему клиент для вашего веб-сервиса на другом языке программирования, например, C #, и он может использовать XML-схему для генерации кода для клиента.
XML-схема является широко распространенным стандартом, который не привязан к конкретному языку программирования. Используя XML-схему и предоставляя ее своим клиентам, вы облегчаете использование веб-службы Restful. Ваши клиенты имеют стандартизированную спецификацию именно того, что им нужно отправить.
Сгенерированные JAXB классы для веб-служб Restful
В этой статье я покажу вам, как настроить проект Maven для создания Jar-файла Java-классов, сгенерированных JAXB из XML-схемы.
Создание проекта Maven в IntelliJ
Для целей этого примера я собираюсь использовать IntelliJ для создания проекта Maven. В реальных условиях вы захотите настроить его как независимый проект Maven или как модуль Maven. Это позволит сгенерированным JAXB классам связываться в JAR-файл и повторно использовать его в других проектах или модулях.
1. Создайте новый проект в IntelliJ.
2. Установите GroupId и ArtifactId в диалоговом окне «Новый проект» IntelliJ.
3. Выберите, где хранить проект на вашем диске.
4. IntelliJ подтвердит создание нового каталога. Нажмите ОК.
5. В зависимости от ваших настроек в IntelliJ вас могут попросить импортировать изменения. Я часто отключаю эту функцию при работе с большими сложными проектами Maven по причинам производительности. Если вы видите это диалоговое окно, нажмите «Импортировать изменения».
6. На данный момент вы создали новый проект Maven в IntelliJ. Вы можете видеть, что стандартная структура каталогов Maven была создана.
Создать XML-схему
Первый файл, который мы создадим, — это XML-схема, которую мы будем использовать. Допустим, мы создаем веб-сервис для добавления продукта, и нам нужен объект команды create product.
В нашей XML-схеме мы создаем класс Product, а также класс CreateProductRequest. Это позволит расширить ProductClass и добавить поле для ключа API. Этот файл находится в папке / main / resources. Это местоположение по умолчанию для файлов схемы XML.
jaxb.xsd
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0">
<!--This tells JAXB what package to create the Java classes in-->
<xsd:annotation>
<xsd:appinfo>
<jaxb:schemaBindings>
<jaxb:package name="guru.springframework.domain"/>
</jaxb:schemaBindings>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType name="Product">
<xsd:sequence>
<xsd:element name="productId" type="xsd:integer"/>
<xsd:element name="productDescription" type="xsd:string"/>
<xsd:element name="productPrice" type="xsd:decimal"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CreateProductRequest">
<xsd:complexContent>
<xsd:extension base="Product">
<xsd:attribute name="apikey" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Настроить Maven
Создание проекта в IntelliJ дало нам очень простой файл POM Maven. Вот Maven POM, созданный для нас.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>guru.springframework</groupId>
<artifactId>jaxb-xsd-example</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
Maven Зависимости
Нам нужно добавить три зависимости в наше Maven POM. Первый — это JAXB API, второй — реализация JAXB, и, наконец, третий — для плагина Maven JAXB.
<dependencies>
<!--jaxb support-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
</dependencies>
Maven JAXB Плагин
Далее нам нужно настроить плагин JAXB для Maven для POM Maven.
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
Полное Maven POM
Вот последний Maven POM.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>guru.springframework</groupId>
<artifactId>jaxb-xsd-example</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--jaxb support-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Создание нашего проекта JAXB Maven
Выполнение Maven Package Goal
IntelliJ делает работу с Maven очень простой. В правой части IDE вы увидите кнопку «Проекты Maven», щелкнув по которой откроется диалоговое окно «Проекты Maven». Чтобы построить наш проект, в разделе «Жизненный цикл» дважды щелкните по цели «пакета».
Вы должны увидеть, как Maven работает и строит успешно.
[INFO]
[INFO] --- maven-jar-plugin:2.3.2:jar (default-jar) @ jaxb-xsd-example ---
[INFO] Building jar: /Users/jt/src/springframework.guru/blog/jaxb-xsd-example/target/jaxb-xsd-example-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.410s
[INFO] Finished at: Fri Aug 07 07:23:44 EDT 2015
[INFO] Final Memory: 16M/207M
[INFO] ------------------------------------------------------------------------
Maven Build Artifacts
Maven будет встроен в каталог ‘Target’. Вы можете увидеть классы Java, созданные в IntelliJ.
JAXB генерируемые классы
Мы ожидали два класса, сгенерированных из XML-схемы, которую мы определили.
Product.java
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.11
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2015.08.07 at 07:23:43 AM EDT
//
package guru.springframework.domain;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for Product complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="Product">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="productId" type="{http://www.w3.org/2001/XMLSchema}integer"/>
* <element name="productDescription" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="productPrice" type="{http://www.w3.org/2001/XMLSchema}decimal"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Product", propOrder = {
"productId",
"productDescription",
"productPrice"
})
@XmlSeeAlso({
CreateProductRequest.class
})
public class Product {
@XmlElement(required = true)
protected BigInteger productId;
@XmlElement(required = true)
protected String productDescription;
@XmlElement(required = true)
protected BigDecimal productPrice;
/**
* Gets the value of the productId property.
*
* @return
* possible object is
* {@link BigInteger }
*
*/
public BigInteger getProductId() {
return productId;
}
/**
* Sets the value of the productId property.
*
* @param value
* allowed object is
* {@link BigInteger }
*
*/
public void setProductId(BigInteger value) {
this.productId = value;
}
/**
* Gets the value of the productDescription property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getProductDescription() {
return productDescription;
}
/**
* Sets the value of the productDescription property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setProductDescription(String value) {
this.productDescription = value;
}
/**
* Gets the value of the productPrice property.
*
* @return
* possible object is
* {@link BigDecimal }
*
*/
public BigDecimal getProductPrice() {
return productPrice;
}
/**
* Sets the value of the productPrice property.
*
* @param value
* allowed object is
* {@link BigDecimal }
*
*/
public void setProductPrice(BigDecimal value) {
this.productPrice = value;
}
}
CreateProductRequest.java
Обратите внимание, как этот класс фактически расширяет класс Product.
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.11
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2015.08.07 at 07:23:43 AM EDT
//
package guru.springframework.domain;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for CreateProductRequest complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="CreateProductRequest">
* <complexContent>
* <extension base="{}Product">
* <attribute name="apikey" type="{http://www.w3.org/2001/XMLSchema}string" />
* </extension>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "CreateProductRequest")
public class CreateProductRequest
extends Product
{
@XmlAttribute(name = "apikey")
protected String apikey;
/**
* Gets the value of the apikey property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getApikey() {
return apikey;
}
/**
* Sets the value of the apikey property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setApikey(String value) {
this.apikey = value;
}
}
Вывод
Это просто очень простой пример генерации классификации из XML-схемы с использованием JAXB и Maven. В этом посте я показал вам шаг за шагом, как использовать XML-схему и JAXB для генерации классов Java. Сгенерированные классы объединены в файл JAR, который является переносимым и может использоваться совместно с другими проектами Java.
Будучи консультантом Spring Source, я работал в крупной компании, которая разработала несколько API Restful. Команда разработчиков API не использовала JAXB для генерации классов из XML-схемы. Скорее они создавали классы JAXB вручную и не могли предложить своим клиентам XML-схему. Как потребитель их API, это был трудоемкий процесс настройки и устранения неполадок моих типов данных.
Я также консультировался в организациях, где команда использовала XML-схемы для создания своих API. Наличие схемы XML сделало написание клиентского кода несложным.
Ресурсы
JAXB
Вы можете найти документацию по проекту JAXB здесь .
JAXB Maven Плагин
Я использовал настройки по умолчанию для плагина JAXB Maven. Дополнительные опции доступны. Документация для плагина JAXB Maven находится здесь .
Исходный код проекта
Исходный код, используемый в этом руководстве, доступен на Github здесь .