Как конвертировать модели Play Framework в XML и JSON?

Существует ли в платформе воспроизведения Нативный или Рекомендуемый способ преобразования моделей Play в XML/JSON? Что-то похожее на JAXB или Jackson.

Некоторые люди рекомендуют шаблонный подход, но это очень многословно и не гарантирует корректного XML/JSON.

Воспроизвести документацию по XML просто показывает, что XML-ответ строится с использованием конкатенации строк следующим образом:

return ok("<message \"status\"=\"OK\">Hello " + name + "</message>");

Аналогично, Play Documentation на JSON показывает, что объект JSON строится по одной строке за раз.

ObjectNode result = Json.newObject();
result.put("status", "OK");
result.put("message", "Hello " + name);

Существует ли Стандартный способ сериализации моделей в XML/JSON с помощью Play?

Есть ли официальная форматная документация на эту тему?

Ответ 1

Короткий ответ: Jackson для JSON и JAXB для XML

Play сам не предоставляет никакой документации по моделям сортировки, но поставляется с Сторонних библиотек, которые могут выполнять эту работу.


JSON:

Модель:

public class User extends Model {
    public String username;
    public Long   age; 

    @JsonIgnore
    public String password; // field won't be marshalled
}

Отметьте его JSON с помощью метода jackson ObjectMapper.writeValueAsString().

import org.codehaus.jackson.map.ObjectMapper;
//
ObjectMapper mapper     = new ObjectMapper();
String       jsonString = mapper.writeValueAsString(country);

Выход JSON:

{
    "username" : "John Smith",
    "age"      : "25"
}

XML:

Необходимо проявлять осторожность из-за того, как Play генерирует геттеры и сеттеры для него модели под капотом. Вы не увидите получателей и сеттеров в коде, но они существуют во время выполнения.

В этой модели важно установить аннотацию XmlAccessorType в PROPERTY. Это говорит JAXB для сериализации из getter/seters, а не из базовых полей.

@XmlAccessorType(XmlAccessType.PROPERTY)

Мы также должны добавить аннотацию @XmlRootElement, которая указывает имя корневого XML node:

@XmlRootElement(name = "UserRoot")

Чтобы опустить поле, мы должны добавить аннотацию @XmlTransient к получателю. Поскольку в исходном коде отсутствует getter, мы должны добавить один для каждого поля, которое мы хотим опустить.

@XmlAccessorType(XmlAccessType.PROPERTY)
public class User extends Model {
    public String username;
    public Long   age;

    @JsonIgnore
    public String password;


    @XmlTransient // This means ignore this property
    public String getPassword() {
        return this.password;
    }
}

Маршаллинг выполняется классами JAXB Marshaller и JAXBContext

JAXBContext context    = JAXBContext.newInstance(User.class);
Marshaller  marshaller = context.createMarshaller();

// Use linefeeds and indentation in the outputted XML
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

marshaller.marshal(user, System.out);

Вывод:

<UserRoot>
    <name>John Smith</name>
    <age>25</age>
</UserRoot>

Резюме:

Воспроизвести документы в формате XML и Воспроизвести документы на JSON Предоставлять некоторую информацию о работе с json/xml, но, похоже, нет ни одного Play Docs, описывающего, как сделать Маршаллинг. Для этого мы должны посмотреть сторонние библиотеки и документацию.

Ответ 2

Для JSON я бы предложил использовать... org.codehaus.jackson, поскольку он доступен как play.libs.Json в Play 2/x @см.: Json Doc

Для XML - шаблонный подход достаточно справедлив, так как вы можете отобразить правильный XML с представлением.

Edit:

Json и Ebean

К сожалению, у Ebean есть проблемы с сериализацией своих объектов в JSON, поэтому я всегда использую выделенный внутренний класс (в целевой модели, которая содержит только поля, которые должны быть отправлены в Json), т.е. для User модель:

public static class ForJson {
    public Long id;
    public String name;
    public String email;

    public ForJson(User user) {
        this.id = user.id;
        this.name = user.name;
        this.email=user.email;
    }
}

маршруты:

GET     /users/all.json            controllers.Application.listUsersJson
GET     /users/all-details.json    controllers.Application.listUsersJsonWithDetails
GET     /users/:id.json            controllers.Application.singleUserJson(id: Long)

действия:

public static Result listUsersJson() {
    List<User.ForJson> usersToJson = new ArrayList<>();
    for (User user : User.find.all()) {
        usersToJson.add(new User.ForJson(user));
    }
    return ok(Json.toJson(usersToJson));
}

public static Result singleUserJson(Long id) {
    User.ForJson userForJson = new User.ForJson(User.find.byId(id));
    return ok(Json.toJson(userForJson));
}

public static Result listUsersJsonWithDetails() {
    Map<String, Object> details = new LinkedHashMap<>();

    List<User.ForJson> usersToJson = new ArrayList<>();
    for (User user : User.find.all()) {
        usersToJson.add(new User.ForJson(user));
    }

    details.put("date", new Date());
    details.put("count", usersToJson.size());
    details.put("users", usersToJson);

    return ok(Json.toJson(details));
}

Да, я знаю, может быть, это redunt и кодирование, но у меня есть хотя бы правильный JSON-выход, и мне не нужно создавать JSON по строкам в каждом действии.

XML:

HTML-символы не нарушают рендеринг правильного XML, так как по умолчанию воспроизводятся шаблоны воспроизведения, поэтому вместо <, >, " он будет использовать &lt;, &gt, &quot; внутри XML node:

<sample>Say &quot;ellou&quot;<sample>

Отметьте Экранирование абзаца в документе docs (внизу страницы).

Чем больше вы можете использовать частичные шаблоны - теги, чтобы убедиться, что один элемент будет отформатирован точно так же в обоих: users/1.xml и users/all.xml

Ответ 3

Существует лучший способ для преобразования JSON.

User user = new User("...");
String jsonString = Ebean.json().toJson(user);