Статьи

JAX-RS 2.x против Spring MVC: возвращение XML-представления списка объектов

JSON — король, поскольку он подходит ко всем видам API-интерфейсов REST *, но, тем не менее, вам может потребоваться предоставить несколько представлений, включая XML. И с JAX-RS, и с Spring MVC это очень просто. На самом деле, единственное, что нужно сделать — это аннотировать POJO, возвращенные из вызова API, с помощью аннотации JAXB, и все.

Но когда дело доходит до сериализации списка объектов, JAX-RS будет немного лучше, чем Spring MVC, на мой взгляд. Давайте посмотрим.

POJO

Единственное требование к обоим (при условии использования JAXB) — аннотировать POJO с помощью аннотации JAXB:

1
2
3
4
@XmlRootElement
public class Incident {
 
}

JAX-RS Way

1
2
3
4
5
@GET
@Path("user/{userId}/incident")
public List<Incident> getUserIncidents(@PathParam("userId") long userId) {
    // return
}

Когда вышеуказанный метод выполняется с application/json качестве принятого представления, JAX-RS будет правильно сериализовать возвращаемый список в JSON, как показано ниже:

01
02
03
04
05
06
07
08
09
10
[
  {
    "description": "Lorem ipsum..." ,
    "status": "NEW"
  },
  {
    "description": "Lorem ipsum..." ,
    "status": "NEW"
  }
]

Никаких специальных объектов-оберток. Результирующий XML может выглядеть следующим образом:

01
02
03
04
05
06
07
08
09
10
<incidents>
    <incident>
        <description>Lorem ipsum ...</description>
        <status>NEW</status>
    </incident>
    <incident>
        <description>Lorem ipsum ...</description>
        <status>NEW</status>
    </incident>
</incidents>

Это просто работает. Нет объектов обертки. Никакой дополнительной работы. Мы сделали.

Spring MVC Way (JAXB)

Как бы вы сделали это весной (скажем, Spring Boot, поскольку он самый быстрый для начала)?

1
2
3
4
@RequestMapping(value = "user/{userId}/incident")
public List<Incident> getUserIncidents(@PathVariable("userId") long userId) {
    // return
}

Однажды JSON-представление запрашивается следующим запросом:

1
$ curl -i http://localhost:8080/user/3/incident

Результат такой же, как в случае JAX-RS.

Чтобы сервер отображал XML вместо JSON, вам может потребоваться отправить заголовок Accept: text/xml :

1
$ curl -i -H "Accept: text/xml" http://localhost:8080/user/3/incident

Но результат будет: 406 Недопустимо. Не удалось найти приемлемое представление в этом случае.

Spring MVC Way (jackson-dataformat-xml)

Spring MVC предлагает решение, которое будет работать «из коробки», аналогично JAX-RS, но с несколько худшим выходом. Решение использует jackson-dataformat-xml. Добавьте зависимость к вашему проекту:

1
2
3
4
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

С новой зависимостью вызов представления XML должен возвращать что-то вроде этого:

01
02
03
04
05
06
07
08
09
10
<ArrayList>
    <item>
        <description>Lorem ipsum ...</description>
        <status>NEW</status>
    </item>
    <item>
        <description>Lorem ipsum ...</description>
        <status>NEW</status>
    </item>
</ArrayList>

Обратите внимание, что использование JAXB-аннотаций не требуется с jackson-dataformat-xml.