2015/04/04 このエントリーをはてなブックマークに追加 はてなブックマーク - 【Kotlin】KotlinでもJava EE 8 のMVC1.0(Ozark)は動くよ

【Kotlin】KotlinでもJava EE 8 のMVC1.0(Ozark)は動くよ




Kotlin meets Java EE 8!!!


KotlinサイトとGlass Fishサイトより引用




はい、動きます。
しなくてもいい苦労をしたくなる僕です。




元ネタ
MVC 1.0(Java EE 8)をとりあえず動かしてみた - Java EE 事始め!

Java EE 8 のearly draftとやら。MVC1.0と言われるJAX-RSとかあたりによく似てる気がしないでもないやつです。





ビルドツール Mavenでやってみます。
正直このぐらいならIDE無くても(頑張れば)出来ます。
IDEとしてEclipseで、Kotlinプラグインを試してみたんだけど上手く行かず。。。。アルファ版出たのに。

・Win7だと上手く言ったんですが、Mac OSXだからなのか。







・Java EE 8動く環境の準備。GlassFish 4.1とか
・プロジェクト作成
・pom変更
・web.xml作成(空のやつ。mvn clean packageで文句言われるから)
・クラス作成
・jsp作成




はしょります



makingさんのブログがとても参考になった。

Kotlinことはじめ - BLOG.IK.AM


ということでだいたいこんな感じで出来上がる。
mvn -B archetype:generate -DgroupId=kotlinweb -DartifactId=kotlin-web -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-quickstart

今回はEclipseで使おうかなぁという気分なので、

mvn eclipse:eclipse


で、Eclipseのプロジェクトファイルも作っておく。





pomはこんな感じに変えます。



<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>hello</groupId>
    <artifactId>kotlin-web</artifactId>
    <packaging>war</packaging>
    <version>1.0.0-SNAPSHOT</version>
    <name>KotlinWeb</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
        <dependency>
            <groupId>com.oracle.ozark</groupId>
            <artifactId>ozark</artifactId>
            <version>1.0.0-m01</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>KotlinWeb</finalName>
        <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
        <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>${kotlin.version}</version>
                <configuration />
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>process-test-sources</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <properties>
        <kotlin0.11.91.1</kotlin
        <projectUTF-8</project
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>
</project>



よし、これでpomに僕は今後困らない(たぶん)。





ブランクというか、すっからかんの作ります。

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
</web-app>





ということで、この作業不要でした!!!
pomのmavenのwarプラグインの設定で解決できます。




これに関しても元記事のほぼパクリですね。
丸パクリも味気無いので、足し算するアプリケーションに変更してみました。


まず、アプリケーションクラス。
MyApplication.kt
package ozarksample

import javax.ws.rs.ApplicationPath
import javax.ws.rs.core.Application

[ApplicationPath("calc")]
public class MyApplication : Application() { 
}



続いて、コントローラクラス
CalcController.kt
package ozarksample.controller

import com.oracle.ozark.engine.JspViewEngine
import javax.enterprise.context.RequestScoped
import javax.inject.Inject
import javax.mvc.Controller
import javax.mvc.Models
import javax.mvc.Viewable
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.PathParam
import java.math.BigDecimal as Decimal

[Path("add")] RequestScoped
public open class CalcController() {
    
    
    private Inject var models : Models? = null
    private val pattern = "\\d{1,}".toRegex() 
    
   
    open fun isNumericLeftAndRight(left : String, right : String) = pattern.matcher(left).matches() && pattern.matcher(right).matches()
    
    open fun putToModels(kvList : List<Pair<String, String>>) {
        kvList.forEach{ models?.put(it.component1(), it.component2()) }
    }
    
    open fun add(left : String, right : String) = Decimal(left).add(Decimal(right)).toString() 
    
    GET Controller [Path("{left}/{right}")]
    open fun calc([PathParam("left")] left : String, [PathParam("right")] right : String) : String {
        if (!isNumericLeftAndRight(left, right)) {
            return "error.jsp"
        }
    
        val formulaAndAnswer = listOf(
            Pair("left", left),
            Pair("right", right),
            Pair("answer", add(left, right))
        )
        putToModels(formulaAndAnswer)
        return "result.jsp";
    }    
}







これも特に個性なし。

error.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>えらーっぽい<h1>
    </body>
</html>


result.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <%-- EL式でnameを表示 --%>
        <h1>${left} + ${right} = ${answer}</h1>
    </body>
</html>






mvn clean packageして出来上がったwarをホホイとデプロイ!



そんでこう!
http://localhost:8080/KotlinWeb/calc/add/1/1にアクセス





続いてこう! そんでこう!
http://localhost:8080/KotlinWeb/calc/add/hogehoge/1にアクセス







ということで、簡単にクソアプリが出来ましたとさ。




KotlinでJava EE関連のあれこれするのは辛い。
Java EEはJavaのためにあるのであって、
おとなしくKotlin好きな人はWasabiとかkara使おう!


辛いところは。。。。
・フィールドインジェクションが辛い
・open付けないといけないのが辛い


コンストラクタインジェクションにしようかと思ったけど、
CDIでは引数なしのコンストラクタも求められるので、
美しく書けなかった。

siosioさんがやってるみたいにコンストラクタインジェクションが出来れば
varとnullリテラル潰せてちょっとKotlinらしくなるんだけどなぁ。

ということで、そこだけ見ればKotlinでSpring boot使ったほうがいいかなとか
(それでも辛さありそうだけど笑)

KotlinでSpring Bootしてみた - しおしお(´・ω・`)
Kotlin M11からはマルチコンストラクタに対応したが、それでも綺麗には書けないのよね。


こういう感じにしか書けなかったし、これだとインジェクションが上手く行かなかった。
(ここらへんは僕の勘違いがあるかもしれないし、今後仕様が変わる可能性がある)

class="code">public open class CalcController {
    
    
    private Inject var models : Models? = null
    constructor () {
    }
    constructor (val models : Models) {
        this.models = models
    }
    
}




こういうのも考えたが、上手く動いてくれなかった。あたりまえだけど。

public open class CalcController {
    constructor () {
    }
    constructor (val models : Models) {
        GET Controller [Path("{left}/{right}")]
        open fun calc([PathParam("left")] left : String, [PathParam("right")] right : String) : String {
            if (!isNumericLeftAndRight(left, right)) {
                return "error.jsp"
            
    
            val formulaAndAnswer = listOf(
                Pair("left", left),
                Pair("right", right),
                Pair("answer", add(left, right))
            )
            putToModels(formulaAndAnswer)
            return "result.jsp";
        }    
    }    
}




openつけないといけないのは、MVC1.0がfinalなメソッドを許してくれないから。
あと、このサンプルだとコントローラーの責務でかくなってきそうだし
Fatな感じになってるのは許して・・・!



という感じでした。






0 件のコメント:

コメントを投稿