Подтвердить что ты не робот

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

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

Теперь я хотел бы использовать эту классную функциональность JSON-ifying для целей, отличных от 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 для таких потребностей, как мой? Мне не повезло найти его до сих пор...

Спасибо!

UPDATE 2009-07-09. Я узнал, что могу использовать объект "Провайдеры", чтобы сделать именно то, что я хочу:

  @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? Спасибо!

4b9b3361

Ответ 1

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

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

http://wiki.fasterxml.com/JacksonJAXBAnnotations

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

Ответ 3

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

Ответ 4

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

List myArray = new ArrayList();

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

С небольшим специфическим бутстрапированием в Джерси вы можете использовать его для создания необходимых объектов JSON для вас. Вам нужно включить следующие зависимости (вы можете использовать пакет, но это вызовет проблемы, если вы используете 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; }
}

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

    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, и намного сложнее, чем необходимо.

Ответ 7

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

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

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

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