Gradle を使っていることだし、アプリも Groovy で書いてみるかと思っていたところ、昨日は IDEA 15 のサジェストに負けて Kotlin を書いてしまいましたが、今日こそは Groovy で書いてみようということで。
ミニマルな build.gradle はこんな感じでしょうか。
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.0.RELEASE")
classpath("org.springframework:springloaded:1.2.4.RELEASE")
}
}
apply plugin: 'groovy'
apply plugin: 'spring-boot'
apply plugin: 'idea'
idea {
module {
inheritOutputDirs = false
outputDir = file("$buildDir/classes/main/")
}
}
sourceSets {
main.groovy.srcDirs += 'src/main/groovy'
}
repositories {
mavenCentral()
}
dependencies {
compile("org.codehaus.groovy:groovy-all")
compile("com.fasterxml.jackson.datatype:jackson-datatype-jdk8")
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
./gradlew idea
でセットアップ後に Groovy でコードを書いていきます。
Groovy は Kotlin のように ? 型がないので java.util.Optional
を使います。Spring Boot が JSON のレンダリングに使う Jackson はデフォルトで Optional をよしなに扱ってくれないので dependencies に追加しておいた jackson-datatype-jdk8
の Jdk8Module
を設定しておきます。
package friendlist
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
@Configuration
@EnableAutoConfiguration
@ComponentScan
class Application {
@Configuration
static class JacksonModuleConfiguration {
@Bean
Jdk8Module javaOptionalModule() {
new Jdk8Module()
}
}
static void main(String[] args) {
SpringApplication.run(Application.class, args)
}
}
Groovy は Java のコードを貼り付けた後にいじれるのが手軽でいいですね。ただ、static def main
とか書きたくなるけど、書けないのですよねぇ..
You can think of def as an alias of Object and you will understand it in an instant.
http://www.groovy-lang.org/semantics.html#_variable_definition
次に Kotlin の例と同様に model と Controller を書きます。
package friendlist.model
class Friend {
Integer id
Optional<String> name
private static ALL_FRIENDS = Arrays.asList(
new Friend(id: 1, name: Optional.of("Alice")),
new Friend(id: 2, name: Optional.of("Bob")),
new Friend(id: 3, name: Optional.of("Chris")),
new Friend(id: 4, name: Optional.of("Denny")),
)
static List<Friend> findAll() {
ALL_FRIENDS
}
static Optional<Friend> findById(Integer id) {
Optional.ofNullable(ALL_FRIENDS.find { f -> f.id == id })
}
}
class FriendResponse {
Optional<Friend> friend
}
class FriendsResponse {
List<Friend> friends
}
Groovy は return を書かなくていいのがいいですね。
package friendlist.web
import friendlist.model.Friend
import friendlist.model.FriendResponse
import friendlist.model.FriendsResponse
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class HomeController {
@RequestMapping("/")
// def でも動く
def home() {
showAll()
}
@RequestMapping("/friends")
FriendsResponse showAll() {
new FriendsResponse(friends: Friend.findAll())
}
@RequestMapping("/friends/{id}")
FriendResponse show(@PathVariable Integer id) {
new FriendResponse(friend: Friend.findById(id))
}
}
これを ./gradlew bootRun
で起動。Spring Loaded が有効になっていて、今回も Groovy のコードを変更すると Spring の設定再読み込みや static なものの細かいケース以外は hot reloading されます。
$ curl -v localhost:8080/
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 25 Nov 2015 12:43:38 GMT
<
* Connection #0 to host localhost left intact
{"friends":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"},{"id":3,"name":"Chris"},{"id":4,"name":"Denny"}]}
$ curl -v localhost:8080/friends/1
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /friends/1 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 25 Nov 2015 12:43:44 GMT
<
* Connection #0 to host localhost left intact
{"friend":{"id":1,"name":"Alice"}}
$ curl -v localhost:8080/friends/10
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /friends/10 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 25 Nov 2015 12:43:46 GMT
<
* Connection #0 to host localhost left intact
{"friend":null}
これもスムーズでした。Gradle + Spring Boot は手軽でよいですね。