IK.AM

@making's tech note


SpringMVC 4.1のProtocol Buffers対応を試す

🗃 {Programming/Java/org/springframework/web}
🏷 Protocol Buffers 🏷 Spring 🏷 Spring MVC 
🗓 Updated at 2014-10-11T15:11:59Z  🗓 Created at 2014-10-11T15:11:59Z   🌎 English Page

Spring MVC 4.1から対応したGoogleのProtocolBuffers対応を試してみます。(4.1.0だとバグって動きません)

Spring 4.1に対応した、Spring Boot 1.2(M2)を使っています。

Protoファイルはチュートリアルのものを使います。

Controllerの書き方はJSONというかRESTの場合と同じです。

package com.example.tutorial;

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

@RestController
public class AddressBookController {
    @RequestMapping("person")
    AddressBookProtos.Person person() {
        return AddressBookProtos.Person.newBuilder()
                .setId(1234)
                .setName("John Doe")
                .setEmail("jdoe@example.com")
                .addPhone(
                        AddressBookProtos.Person.PhoneNumber.newBuilder()
                                .setNumber("555-4321")
                                .setType(AddressBookProtos.Person.PhoneType.HOME))
                .build();
    }
}

Spring側の対応としては、@RestControllerを使ったときに通るorg.springframework.http.converter.HttpMessageConverterのProtobuf実装(org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter)を追加しています。

JavaConfigにこのHttpMessageConverterを追加します。

package com.example.tutorial;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;

@Configuration
public class AppConfig {
    @Bean
    ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter((extensionRegistry) -> {
        });
    }
}

あとはいつも通りSpring Bootのエントリポイントを作るだけ

package com.example.tutorial;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

@EnableAutoConfiguration
@ComponentScan
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

このAppを実行して、アクセスすると

$ curl http://localhost:8080/person

John Doe�	jdoe@example.com"

555-4321

こんな感じです。

テストはこんな感じ。(RestTemplate使うので十分だった・・)

package com.example.tutorial;

import com.jayway.restassured.RestAssured;
import com.jayway.restassured.response.ResponseBodyData;
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.when;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

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

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

    @Test
    public void testPerson() throws Exception {
        ResponseBodyData body = when().get("/person")
                .then()
                .extract()
                .body();
        AddressBookProtos.Person person = AddressBookProtos.Person.parseFrom(body.asInputStream());

        assertThat(person.getName(), is("John Doe"));
        assertThat(person.getId(), is(1234));
        assertThat(person.getEmail(), is("jdoe@example.com"));
        assertThat(person.getPhoneList(), hasSize(1));
        assertThat(person.getPhone(0).getNumber(), is("555-4321"));
        assertThat(person.getPhone(0).getType(), is(AddressBookProtos.Person.PhoneType.HOME));
    }
}

せっかくなのでPythonからもアクセスしてみます。

import httplib
import addressbook_pb2

conn = httplib.HTTPConnection("localhost", 8080)
conn.request("GET", "/person")
res = conn.getresponse()
body = res.read()
conn.close()

person = addressbook_pb2.Person()
person.ParseFromString(body)
print person

Python2系ですいません・・

$ python test.py 
name: "John Doe"
id: 1234
email: "jdoe@example.com"
phone {
  number: "555-4321"
  type: HOME
}

いけました。

HTTP経由だとJSONに比べてどのくらいメリットあるんだろう・・・

ソースコードはGithubに上げました。


✒️️ Edit  ⏰ History  🗑 Delete