55

私はJerseyを使用して、サーバーコンポーネント用のRESTWebサービスを作成しています。

リストでシリアル化したいJAXB注釈付きオブジェクトは次のようになります。

@XmlRootElement(name = "distribution")
@XmlType(name = "tDistribution", propOrder = {
    "id", "name"
})
public class XMLDistribution {
    private String id;
    private String name;
    // no-args constructor, getters, setters, etc
}

次のような1つのディストリビューションを取得するためのRESTリソースがあります。

@Path("/distribution/{id: [1-9][0-9]*}")
public class RESTDistribution {
    @GET
    @Produces("application/json")
    public XMLDistribution retrieve(@PathParam("id") String id) {
        return retrieveDistribution(Long.parseLong(id));
    }
    // business logic (retrieveDistribution(long))
}

また、すべてのディストリビューションのリストを取得するためのRESTリソースがあります。これは次のようになります。

@Path("/distributions")
public class RESTDistributions {
    @GET
    @Produces("application/json")
    public List<XMLDistribution> retrieveAll() {
        return retrieveDistributions();
    }
    // business logic (retrieveDistributions())
}

ContextResolverを使用してJAXBシリアル化をカスタマイズします。これは、現在次のように構成されています。

@Provider
@Produces("application/json")
public class JAXBJSONContextResolver implements ContextResolver<JAXBContext> {
    private JAXBContext context;
    public JAXBJSONContextResolver() throws Exception {
        JSONConfiguration.MappedBuilder b = JSONConfiguration.mapped();
        b.nonStrings("id");
        b.rootUnwrapping(true);
        b.arrays("distribution");
        context = new JSONJAXBContext(b.build(), XMLDistribution.class);
    }
    @Override
    public JAXBContext getContext(Class<?> objectType) {
        return context;
    }
}

両方のRESTリソースと、コンテキストリゾルバーが機能します。これは、最初のものの出力の例です。

// path: /distribution/1
{
  "id": 1,
  "name": "Example Distribution"
}

それはまさに私が欲しいものです。これは、リストの出力例です。

// path: /distributions
{
  "distribution": [{
    "id": 1,
    "name": "Sample Distribution 1"
  }, {
    "id": 2,
    "name": "Sample Distribution 2"
  }]
}

これは私が望んでいることではありません。

distributionなぜそこに囲みタグがあるのか​​わかりません。.rootUnwrapping(true)コンテキストリゾルバーでそれを削除したかったのですが、どうやらそれは別の囲んでいるタグを削除するだけです。これは次の出力.rootUnwrapping(false)です:

// path: /distribution/1
{
  "distribution": {
    "id": 1,
    "name": "Example Distribution"
  }
} // not ok
// path: /distributions
{
  "xMLDistributions": {
    "distribution": [{
      "id": 1,
      "name": "Sample Distribution 1"
    }, {
      "id": 2,
      "name": "Sample Distribution 2"
    }]
  }
}

.arrays("distribution")また、要素が1つしかない場合でも、常にJSON配列を取得するように構成する必要がありました。

理想的には、これを出力として使用したいと思います。

// path: /distribution/1
{
  "id": 1,
  "name": "Example Distribution"
} // currently works
// path: /distributions
[{
  "id": 1,
  "name": "Sample Distribution 1"
}, {
  "id": 2,
  "name": "Sample Distribution 2"
}]

List<XMLDistribution>XMLDistributionList(リストのラッパー)、、を返そうとしましたXMLDistribution[]が、必要な形式でディストリビューションの単純なJSON配列を取得する方法が見つかりませんでした。

JSONConfiguration.natural()、などによって返される他の表記法も試しましたがJSONConfiguration.mappedJettison()、必要なものに似たものを取得できませんでした。

これを行うようにJAXBを構成できるかどうか誰かが知っていますか?

4

2 に答える 2

104

私は解決策を見つけました: JAXB JSON シリアライザーを Jackson のような動作の良い JSON シリアライザーに置き換えます。簡単な方法は、既に実行済みの jackson-jaxrs を使用することです。クラスは JacksonJsonProvider です。プロジェクトの web.xml を編集して、Jersey (または別の JAX-RS 実装) がスキャンできるようにするだけです。追加する必要があるものは次のとおりです。

<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>your.project.packages;org.codehaus.jackson.jaxrs</param-value>
</init-param>

それだけです。Jackson は JSON シリアライゼーションに使用され、リストと配列に対して期待どおりに機能します。

より長い方法は、「application/json」を生成するために登録された独自のカスタム MessageBodyWriter を作成することです。次に例を示します。

@プロバイダ
@Produces("アプリケーション/json")
public class JsonMessageBodyWriter は MessageBodyWriter を実装します {
    @オーバーライド
    public long getSize(Object obj, Class type, Type genericType,
            Annotation[] 注釈、MediaType mediaType) {
        -1 を返します。
    }

    @オーバーライド
    public boolean isWriteable(クラス型、型ジェネリック型、
            注釈 注釈[]、MediaType mediaType) {
        true を返します。
    }

    @オーバーライド
    public void writeTo(オブジェクト ターゲット、クラス タイプ、タイプ genericType、
            Annotation[] 注釈、MediaType mediaType、
            MultivaluedMap httpHeaders、OutputStream outputStream)
            IOException をスローします {        
        new ObjectMapper().writeValue(outputStream, target);
    }
}

上記の既製のソリューションと同様に、web.xml にパッケージが含まれていることを確認する必要があります。

いずれにせよ、ほら!適切に形成された JSON が表示されます。

ここから Jackson をダウンロードできます: http://jackson.codehaus.org/

于 2010-06-29T17:32:08.707 に答える
13

Jonhatan の回答は素晴らしく、私にとって非常に役に立ちました。

ただのアップグレード:

Jackson のバージョン 2.x (バージョン 2.1 など) を使用する場合、クラスは com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider であるため、web.xml は次のようになります。

<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>your.project.packages;com.fasterxml.jackson.jaxrs.json</param-value>
</init-param>
于 2013-04-15T20:43:57.387 に答える