mike-neckのブログ

Java or Groovy or Swift or Golang

儂のIntelliJ IDEAとGradle力が足りなくてJavaEEプロジェクトで困った件

JavaEEの本を読もうとしてIDENetBeansだけど儂のIDEAとGradle力で余裕で対応できるでしょうとタカを括っていたら、見事に挫折しました(´・ω・`)

で、今日一日もかかって、気合でIntelliJ IDEAでもちゃんと開発できるようにbuild.gradle書いたので、そのメモ。決してこのスクリプトでデプロイできるとは言っていない。

前提

プロジェクトの構造

  • jpaのサブプロジェクト
  • webのサブプロジェクト(jpaに依存)
  • applicationのサブプロジェクト(webに依存。これの成果物をサーバーで動かす)

環境

  • IntelliJ IDEA 14.0.3
  • Gradle(バージョン忘れた。多分2.3くらい)
  • GlassFish4.1.0

build.gradleとideaタスク

ideaタスクで作成されるIntelliJ IDEA用のファイルはhoge.iprhoge.imlおよび、サブプロジェクトのsubproject.imlファイルです。で、これらのファイルのうち、hoge.iprファイルとsubproject.imlファイルにJavaEE開発の成果物を設定してやることで、IntelliJ IDEAからGlassFishを起動した時に開発しているアプリケーションをGlassFishで動かすことができます。

hoge.iprファイル

ここにはartifactの設定を記述します。

subproject.imlファイル

ここにはfacet(webプロファイルとかjavaeeのプロファイルとか)の設定を記述します。

build.gradle

で、説明が面倒なのでビルドスクリプトを書くと次のとおり

apply plugin: 'idea'
allprojects {
    apply plugin: 'idea'
}
project(':jpa'){
    //省略
}
project(':web'){
    apply plugin: 'war'
    dependencies {
        compile project(':jpa')
        providedCompile 'javax.javaee-api:7.0'
    }
    idea {
        module {
            iml {
                //webプロジェクトがwebアプリケーションのプロジェクトであるとIDEAに認識させる
                withXml {
                    def node = it.asNode()
                    def f = new NodeBuilder()
                    def facet = f.component(name: 'FacetManager') {
                        facet(type: 'web', name: 'Web') {
                            configuration {
                                descriptors {
                                    deploymentDescriptor(name: 'web.xml', url: "file://${projectDir}/src/main/webapp/WEB-INF/web.xml")
                                }
                                webroots {
                                    root(url: "file://${projectDir}/src/main/webapp", relative: '/')
                                }
                                sourceRoots {
                                    ['java', 'resources'].each {
                                        root(url: "file://${projectDir}/src/main/${it}")
                                    }
                                }
                            }
                        }
                    }
                    node.append(facet)
                }
            }
        }
    }
}
project(':app'){
    apply plugin: 'ear'
    dependencies {
        deploy project(':web')
    }
    idea {
        module {
            iml {
                withXml {
                    def node = it.asNode()
                    def f = new NodeBuilder()
                    //appプロジェクトがjavaeeアプリケーションのプロジェクトであるとIDEAに認識させる
                    def facet = f.component(name: 'FacetManager') {
                        facet(type: 'javaeeApplication', name: 'javaee') {
                            configuration()
                        }
                    }
                    node.append(facet)
                }
            }
        }
    }
}
idea {
    project {
        languageLevel = jdkLevel
        ipr {
            withXml {xml ->
                def node = xml.asNode()
                def f = new NodeBuilder()
                def component = f.component(name: 'ArtifactManager') {
                    //appプロジェクトの成果物がjavaeeアプリケーションであるとIDEAに認識させる
                    artifact(type: 'exploded-ear', name: 'javaee') {
                        //アプリケーションの出力先を設定(アプリケーションのコンテキストルートが設定される)
                        'output-path' "${projectDir}/out/artifacts/javaee-app"
                        root(id: 'root') {
                            element(id: 'javaee-facet-resources', facet: 'app/javaeeApplication/javaee')
                            element(id: 'artifact', 'artifact-name': 'web')
                        }
                    }
                    //webプロジェクトの成果物がwebアプリケーションであるとIDEAに認識させる
                    artifact(type: 'exploded-war', name: 'web') {
                        'output-path' "${projectDir}/out/artifacts/web"
                        root(id: 'root') {
                            element(id: 'javaee-facet-resources', facet:'web/web/Web')
                            element(id: 'directory', name: 'WEB-INF') {
                                element(id: 'directory', name: 'classes') {
                                    element(id: 'module-output', name: 'web')
                                    element(id: 'module-output', name: 'jpa')
                                }
                                element(id: 'directory', name: 'lib') {
                                    project(':jpa').configurations.compile.findAll{!it.name.contains('javaee-api')}.each {
                                        element(id: 'file-copy', path: it)
                                    }
                                }
                            }
                        }
                    }
                }
                node.append(component)
            }
        }
    }
}

技術的に難しいことはしていなくて、ただGroovyのNodeBuilderNodeを作り出して、まだ出力されていないhoge.iprとかsubproject.imlなど(実態はXMLファイル)をNode形式にしたものに追加してやります。一つ注意しておきたいのは、hoge.iprに記述しているアプリケーションの出力先です。これがアプリケーションのコンテキストルートになります。

GlassFishラウンチャーの作成

  • Menu→Edit Configurationsから「Run/Debug Configurations」を起動します。
  • 左上の「+」ボタンを押すと「Add Configuration」という選択肢が表示されるので、「GlassFish」を選択します。
  • Application Serverにて「GlassFish 4.1.0」を選択して(ない場合は「Configure」からGlassFishのインストールディレクトリーを選択します)
  • 「Open Browser」にアプリケーションのURLを記入するところがあるので、先ほどのコンテキストルートの名前を用いて「http:://localhost:ポート番号/コンテキストルート」を入力します。
  • GlassFish Server Settings」にてGlassFishドメインの情報(ドメイン名、ユーザー名、パスワード)を入力します。
  • Before lauchに「Build 'Javaee' artifact」がない場合は、左下の「+」ボタンから「Build Artifact」を選択すると、artifact一覧がポップアップされるので「javaee」を選びます。

Run/Debug Configurations


以上、やっとさっきの本の3章を読み始められそうです