---
title: Apache Johnzon(JSR-353 JSON-P実装ライブラリ)をJAX-RSとSpring MVCで使ってみる
tags: ["JAX-RS", "JSON-P", "Java", "Jersey", "Johnzon", "Spring", "Spring Boot", "Spring MVC"]
categories: ["Programming", "Java", "org", "apache", "johnzon"]
date: 2014-10-27T05:55:55Z
updated: 2014-10-27T12:06:19Z
---

JSON-P(JSR-353)の実装がApacheから出ていたので使ってみた。

* [Apache Johnzon](http://johnzon.incubator.apache.org/)

[JSON-P RI](https://jsonp.java.net)とは異なり、JAX-RS用の`MessageBodyReader`/`MessageBodyWriter`も用意されている(多分)。

これをJAX-RS/Spring MVC両方で使ってみた。どっちもSpring Bootベース。Spring BootでJAX-RSを使う方法[こちら](/#/entries/286)。

サンプルは[Github](https://github.com/making/johnzon-jsr353-demo)にあげた。

## JAX-RS版

### pom.xml

重要なところだけ、

``` xml
<dependencies>
    <!-- JSR-353 -->
    <dependency>
        <groupId>org.apache.geronimo.specs</groupId>
        <artifactId>geronimo-json_1.0_spec</artifactId>
        <version>1.0-alpha-1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.johnzon</groupId>
        <artifactId>johnzon-core</artifactId>
        <version>0.1-incubating</version>
    </dependency>
    <dependency>
        <groupId>org.apache.johnzon</groupId>
        <artifactId>johnzon-jaxrs</artifactId>
        <version>0.1-incubating</version>
    </dependency>

    <!-- omitted -->
</dependencies>
```

### リソースクラス

``` java
package demo;

import org.springframework.stereotype.Component;

import javax.json.Json;
import javax.json.JsonObject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Component
@Path("/")
public class HelloResource {

    @GET
    public JsonObject hello() {
        return Json.createObjectBuilder()
                .add("name", "@making")
                .add("age", 18)
                .build();
    }
}
```


`@Component`はなくてもいい。SpringのDIコンテナ管理のものをDIしたければ必要。

普通JavaBean作るので誰得感が強い。


### Configクラス

``` java
package demo;

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig extends ResourceConfig {
    public AppConfig() {
        packages(true, "demo", "org.apache.johnzon");
    }
}
```

Johnzonが用意している`MessageBodyReader`/`MessageBodyWriter`がスキャンされるように対象パッケージに`org.apache.johnzon`を追加。

エントリポイントはSpring Bootのいつものやつなので省略。

### E2Eテスト

```
package demo;

import com.jayway.restassured.RestAssured;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import static com.jayway.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = App.class)
@WebAppConfiguration
@IntegrationTest({"server.port:0"})
public class HelloResourceTest {
    @Value("${local.server.port}")
    int port;

    @Before
    public void setUp() throws Exception {
        RestAssured.port = port;
    }

    @Test
    public void testHello() throws Exception {

        given().header("Accept", "application/json")
                .log().all()
                .when().get("/").then()
                .log().all()
                .body("name", is("@making"))
                .body("age", is(18));
    }
}
```

`Accept`ヘッダを指定しないとレスポンスの`Content-Type`が`application/octet-stream`になっちゃって、テストユーティリティのRESTAssured側でこけた・・

## Spring MVC版

### pom.xml
重要なところだけ。

``` java
<dependencies>
    <!-- JSR-353 -->
    <dependency>
        <groupId>org.apache.johnzon</groupId>
        <artifactId>johnzon-core</artifactId>
        <version>${johnzon.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr353</artifactId>
        <version>${jackson.version}</version>
    </dependency>

    <!-- omitted -->
</dependencies>
```

Spring MVC用の`MessageConverter`は用意されていないので、代わりにJacksonが用意しているJSR-353用のモジュールを使用します。
(つまりSpring MVCにおいてはJohnzonつかってもRIつかっても大差ない)

### Controller

``` java
package demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.json.Json;
import javax.json.JsonObject;

@RestController
public class HelloController {

    @RequestMapping("/")
    JsonObject hello() {
        return Json.createObjectBuilder()
                .add("name", "@making")
                .add("age", 18)
                .build();
    }
}
```

誰得(略)

### Configクラス

``` java
package demo;

import com.fasterxml.jackson.datatype.jsr353.JSR353Module;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    JSR353Module jsr353Module() {
        return new JSR353Module();
    }
}
```

Jacksonが用意しているJSR-353用の`com.fasterxml.jackson.databind.Module`実装をBean定義して有効にする。


エントリポイントはSpring Bootのいつものやつなので省略。

### E2Eテスト
全く同じ。

----

ソースは[こちら](https://github.com/making/johnzon-jsr353-demo)。
誰得な内容ブログに書くの楽しい。
