簡體   English   中英

如何重用Jersey的JSON / JAXB進行序列化?

[英]How to reuse Jersey's JSON/JAXB for serialization?

我有一個使用Jersey實現的JAX-RS REST服務。 JAX-RS / Jersey的一個很酷的功能就是如何輕松地將POJO變成REST服務,只需簡單地添加一些Java注釋......包括使用JAXB注釋將POJO轉換為JSON的簡單機制。

現在,我希望能夠利用這種非常酷的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中公開了這個功能,以滿足我的需求? 到目前為止我找不到運氣了......

謝謝!

更新2009-07-09 :我已經了解到我可以使用Providers對象幾乎完全按照我的意願行事:

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

  uw.writeTo(....)

...這將對象作為json寫入任何輸出流,這對我來說是完美的,但我只能使用@Component對象中的@Context來獲取Providers對象。 有沒有人知道如何從常規的,未注釋的POJO訪問它? 謝謝!

Jersey使用幾個不同的框架,具體取決於您使用的是mapped(),badgerfish()還是natural()表示法。 自然通常是人們想要的。 我相信這是使用非常好的(並且非常快)獨立的Jackson JSON處理器實現的,它來自Object-> JAXB-> JSON。 但Jackson也提供了自己的JAX-RS提供程序來直接使用Object-> JSON。

實際上,他們甚至添加了對JAXB注釋的支持。 看一下

http://wiki.fasterxml.com/JacksonJAXBAnnotations

我認為這最終是你在尋找的。 傑克遜做對象< - > JSON處理......澤西只是為你打電話

這是一個使用JAXB將對象映射到JSON的簡單示例(使用Jackson):

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

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

在序列化為XML時,JAXB注釋工作正常。 主要問題是JAXB不支持空數組。 所以當序列化這樣的東西時......

List myArray = new ArrayList();

...通過jaxb anottations到json所有空數組都變為null而不是[]。

要解決這個問題,您可以通過jackson直接將您的pojos序列化為json。

從Jersey的用戶指南中查看: http//jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959

這是在沒有JAXB的情況下使用Jackson提供程序的最佳方式。 此外,您可以隨時使用最新版本的jackson,通過網絡下載jackson-all-xyz-jar。

這個方法不會干擾你的jaxb注釋,所以我建議試一試!

通過一點Jersey專用引導,您可以使用它為您創建必要的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\""));

這種方法的優點是它可以保留JEE6 API中的所有內容,除了測試和獲取提供程序之外,不需要明確需要任何外部庫。 但是,您需要創建MultivaluedMap的實現,因為標准中沒有提供任何內容,我們實際上並未使用它。 它也可能比GSON慢,很多復雜得多必要的。

由於Jersey是JAX-RS的參考實現,而JAX-RS完全專注於提供實現REST服務端點的標准方法,因此將有效負載序列化的問題留給其他標准。

我認為,如果它們在JAX-RS標准中包含對象序列化,它很快就會成為一個很難實現的大型多頭野獸,並且會忽略它的一些重點。

我很欣賞Jersey在提供簡潔易用的REST端點方面的重點。 在我的情況下,我只是將一個包含所有JAXB管道的父類子類化,因此二進制和XML之間的編組對象非常干凈。

我理解XML視圖,但它會表現出一些先見之明,需要JSON支持POJO作為標准設備。 如果您的實現是JSON並且您的客戶端是JavaScript RIA,則必須使用特殊字符來管理JSON標識符是沒有意義的。

而且,Java Bean並不是POJO。 我想在我的Web層的外表面上使用類似的東西:

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

沒有默認構造函數,沒有getter / setter噪聲,只有一個帶有我自己的注釋的POJO。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM