2015年8月29日土曜日

Maven pluginでプロジェクトのビルドアウトプットに依存する方法

Guide to Maven Classloadingによると、Maven pluginはPlugin classloaderでクラスがロードされます。
プラグインのdependenciesに設定されたライブラリはロードされるけど、プラグインが設定されたプロジェクトのビルドアウトプットやdependenciesに設定されたライブラリを見ることはできない。

どうしても、プラグインからプロジェクトのビルドアウトプットを参照できないとダメなときは、Mojoでカスタムクラスローダを使ってロードする必要がある。例えば、Mojoから使うライブラリがClassオブジェクトを要求する場合なんかは、自分でカスタムクラスローダ使って頑張る必要がある。

Stackoverflowいい解決案があるので、これを参考に対応するのがよい。→Maven plugin can't load class

自分は、最も+1された回答を参考にしてみました。
やった内容は、大きくしたの2点になります。

MavenProjectをMojoにインジェクトする

Mojoのフィールドで、MavenProjectを受け取ります。
    @Parameter(defaultValue = "${project}", required = true, readonly = true)
    private MavenProject project;

カスタムクラスローダを使ってクラスをロードする

MavenProjectのgetRuntimeClasspathElementsを使って、クラスパスに設定されているパスを取得して、カスタムクラスローダを作ります。
getRuntimeClasspathElementsが返す値は、MojoアノテーションのrequiresDependencyResolution属性に指定した値によって変わります。
属性を指定しない場合は、target/classesだけが取得されます。ResolutionScope.RUNTIMEを設定すると、dependenciesに設定したライブラリも取得されます。
    private URLClassLoader createClassLoader() {
        List runtimeClasspathElements;
        try {
            runtimeClasspathElements = project.getRuntimeClasspathElements();
        } catch (DependencyResolutionRequiredException e) {
            throw new RuntimeException(e);
        }

        final URL[] urls = runtimeClasspathElements.stream()
                .peek(s -> System.out.println("classpath:" + s))
                .map(s -> {
            try {
                return new File(s).toURI().toURL();
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        }).toArray(URL[]::new);
        return new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
    }