Как повторно использовать JSON/JAXB Джерси для сериализации?

StackOverflow https://stackoverflow.com/questions/1071749

  •  21-08-2019
  •  | 
  •  

Вопрос

У меня есть служба REST JAX-RS, реализованная с использованием Джерси.Одной из замечательных особенностей JAX-RS/Jersey является то, насколько легко POJO можно превратить в службу REST, просто добавив несколько аннотаций Java...включая тривиально простой механизм перевода POJO в JSON — с использованием аннотаций JAXB.

Теперь я хотел бы иметь возможность воспользоваться этой замечательной функцией преобразования JSON для целей, отличных от REST: мне бы хотелось иметь возможность просто сериализовать некоторые из этих объектов на диск в виде текста JSON.Вот пример объекта JAXB, который я хотел бы сериализовать:

@XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {

    public UserInfoImpl() {} 

    public UserInfoImpl(String user, String details) {
        this.user = user;
        this.details = details;
    }

    public String getUser() { return user; }
    public void setUser(String user) { this.user = user; }

    public String getDetails() { return details; }
    public void setDetails(String details) { this.details = details; }

    private String user;
    private String details;
}

Джерси может преобразовать один из них в формат JSON без дополнительной информации.Мне интересно, предоставил ли Джерси эту функциональность в API для таких нужд, как моя?Мне пока не удалось его найти...

Спасибо!

ОБНОВЛЕНИЕ 9 июля 2009 г.:Я узнал, что могу использовать объект Providers для почти делаю именно то, что я хочу:

  @Context Providers ps;
  MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);

  uw.writeTo(....)

...При этом объект будет записан в виде json в любой выходной поток, что было бы идеально для меня, но я могу получить доступ к объекту Providers только с помощью @Context из объекта @Component.Кто-нибудь знает, как получить к нему доступ из обычного POJO без аннотаций?Спасибо!

Это было полезно?

Решение

Джерси использует несколько разных фреймворков в зависимости от того, используете ли вы нотацию Mapped(), Badgerfish() или Natural().Естественность обычно является тем, чего люди хотят.И это реализовано с использованием, по моему мнению, очень хорошего (и очень быстрого) автономного процессора Jackson JSON, который идет по схеме Object->JAXB->JSON.Однако Джексон также предоставляет собственного провайдера JAX-RS для прямого перехода Object->JSON.

Более того, они даже добавили поддержку аннотаций JAXB.Посмотри на

http://wiki.fasterxml.com/JacksonJAXBAnnotations

Я думаю, что это, в конечном счете, то, что вы ищете.Джексон выполняет обработку Object<->JSON... Джерси просто звонит за вас.

Другие советы

Вот простой краткий пример использования JAXB для сопоставления объектов с JSON (с использованием Джексона):

http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-jackson-howto.texy

ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);

Аннотации JAXB отлично работают при сериализации в XML.Основная проблема заключается в том, что JAXB не поддерживает пустые массивы.Итак, при сериализации чего-то подобного...

List myArray = new ArrayList();

... в json через аннотации jaxb все ваши пустые массивы становятся нулевыми вместо [].

Чтобы решить эту проблему, вы можете просто сериализовать свои pojo непосредственно в json через jackson.

Взгляните на это из руководства пользователя Джерси:http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959

Это лучший способ использовать провайдера Jackson без JAXB.Более того, вы всегда можете использовать последнюю версию jackson, загрузив jackson-all-xyz-jar из Интернета.

Этот метод не помешает вашим аннотациям jaxb, поэтому я бы посоветовал попробовать!

Поскольку Джерси является эталонной реализацией JAX-RS, а JAX-RS полностью ориентирован на предоставление стандартного способа реализации конечной точки для службы REST, вопросы сериализации полезной нагрузки оставлены на усмотрение других стандартов.

Я думаю, что если бы они включили сериализацию объектов в стандарт JAX-RS, он быстро превратился бы в большого многоголового зверя, которого было бы трудно реализовать и который потерял бы часть своего фокуса.

Я ценю то, насколько Джерси сосредоточен на предоставлении понятных и простых в использовании конечных точек REST.В моем случае я только что создал подкласс родительского объекта, в котором есть вся инфраструктура JAXB, поэтому сортировка объектов между двоичными файлами и XML очень проста.

С помощью небольшой начальной загрузки, специфичной для Джерси, вы можете использовать его для создания необходимых вам объектов JSON.Вам необходимо включить следующие зависимости (вы можете использовать Bundle, но это вызовет проблемы, если вы используете Weld для тестирования):

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.12</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.12</version>
    </dependency>

Оттуда вы можете создать аннотированный класс JAXB.Ниже приведен пример:

@XmlRootElement
public class TextMessage {
private String text;
    public String getText() { return text; }
    public void setText(String s) { this.text = text; }
}

Затем вы можете создать следующий модульный тест:

    TextMessage textMessage = new TextMessage();
    textMessage.setText("hello");
    textMessage.setUuid(UUID.randomUUID());

    // Jersey specific start
    final Providers ps = new Client().getProviders();
    // Jersey specific end
    final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {

        @Override
        public void add(final String key, final Object value) {
        }

        @Override
        public void clear() {
        }

        @Override
        public boolean containsKey(final Object key) {
            return false;
        }

        @Override
        public boolean containsValue(final Object value) {
            return false;
        }

        @Override
        public Set<java.util.Map.Entry<String, List<Object>>> entrySet() {
            return null;
        }

        @Override
        public List<Object> get(final Object key) {
            return null;
        }

        @Override
        public Object getFirst(final String key) {
            return null;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public Set<String> keySet() {
            return null;
        }

        @Override
        public List<Object> put(final String key, final List<Object> value) {
            return null;
        }

        @Override
        public void putAll(
                final Map<? extends String, ? extends List<Object>> m) {
        }

        @Override
        public void putSingle(final String key, final Object value) {
        }

        @Override
        public List<Object> remove(final Object key) {
            return null;
        }

        @Override
        public int size() {
            return 0;
        }

        @Override
        public Collection<List<Object>> values() {
            return null;
        }
    };

    final MessageBodyWriter<TextMessage> messageBodyWriter = ps
            .getMessageBodyWriter(TextMessage.class, TextMessage.class,
                    new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Assert.assertNotNull(messageBodyWriter);

    messageBodyWriter.writeTo(textMessage, TextMessage.class,
            TextMessage.class, new Annotation[0],
            MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
    final String jsonString = new String(baos.toByteArray());
    Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));

Преимущество этого подхода заключается в том, что он сохраняет все в рамках API JEE6, никакие внешние библиотеки явно не нужны, за исключением тестирования и получения поставщиков.Однако вам необходимо создать реализацию MultivaluedMap, поскольку в стандарте ничего не предусмотрено, и мы фактически не используем его.Это может также быть медленнее, чем GSON, и намного сложнее, чем необходимо.

Я понимаю представления XML, но было бы проявлением некоторой предусмотрительности требовать поддержки JSON для POJO в качестве стандартного оборудования.Необходимость дополнять идентификаторы JSON специальными символами не имеет смысла, если ваша реализация — JSON, а клиент — JavaScript RIA.

Кроме того, это не значит, что Java Beans НЕ являются POJO.Я хотел бы использовать что-то вроде этого на внешней поверхности моего веб-уровня:

public class Model
{
   @Property height;
   @Property weight;
   @Property age;
}

Никакого конструктора по умолчанию, никакого шума геттеров/сеттеров, просто POJO с моими собственными аннотациями.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top