2012-03-15 10 views
2

メイプルのプラグインの開発に精通しています。私は1つの質問で助けが必要です。クラスをMaven2プラグインに渡す

私が学んだように、複雑なオブジェクトをMavenプラグインに渡すのは簡単ですが、クラスを渡すのはどうですか? 私は自分のプラグインを書くのは2つのクラスしかないと言うことができます。

Message.java

package abstractmessage; 
public abstract class Message { 
    public abstract String getMessage(); 
} 

MessageMojo.java

/** 
* @goal message 
*/ 
public class MessageMojo extends AbstractMojo { 
    /** 
    * @parameter expression="${message.messageClass}" 
    */ 
    private String messageClass ; 

    @Override 
    public void execute() throws MojoExecutionException, MojoFailureException { 
     Message message = null; 

     try { 
      Class<?> clazz = Class.forName(messageClass); 
      message = (Message) clazz.newInstance(); 
     } catch (Exception e) { 
      getLog().error(e); 
     } 

     getLog().info(message.getMessage()); 
    } 
} 

ので、プラグインが拡張されたメッセージクラスの名前を期待し、それを初期化dynamicalyしようとします。

実際のMaven-Projectの拡張Messageクラスは次のようになります。

package message; 
import abstractmessage.Message; 

public class RealMessage extends Message { 
    @Override 
    public String getMessage() { 
     return "Hello plugin. From MavenProject."; 
    } 
} 

そして、pom.xmlはプラグインを使用します。

<build> 
    <plugins> 
     <plugin> 
      <artifactId>message-plugin</artifactId> 
      <groupId>message-plugin</groupId> 
      <version>1.0</version> 
      <executions> 
       <execution> 
        <phase>test</phase> 
        <goals> 
         <goal>message</goal> 
        </goals> 
       </execution> 
      </executions> 
      <configuration> 
       <messageClass>message.RealMessage</messageClass> 
      </configuration> 
     </plugin> 
    </plugins> 
</build> 

<dependencies> 
    <dependency> 
     <artifactId>message-plugin</artifactId> 
     <groupId>message-plugin</groupId> 
     <version>1.0</version> 
    </dependency> 
</dependencies> 

しかし、私はMavenを実行します。テスト私はなぜjava.lang.ClassNotFoundException: message.RealMessage

を取得しますか?

+0

クラスに明示的に使用されていない場合は、クラス名になるように再解析する文字列でなければなりません。それを行う唯一の方法は自分自身のプラグインを作成することです。 – Neil

答えて

1

あなたのプラグインのクラスローダーは、プロジェクトのクラスにアクセスできません。独自のクラスとその依存関係にのみアクセスできます。

2つのオプションがあります。

オプション1は、現在のプロジェクトとその依存関係からクラスをロードする新しいクラスローダーを作成することです。 surefire pluginはこれを実行するプラグインの一例です。コンパイルされたユニットテストクラスをロードし、フォークモードでない場合はそれらを実行できます。

依存関係から新しいクラスローダーを作成することはまったく簡単なことではありませんが、まずは@requiresDependencyResolution testをMojoに入れて、プロジェクトの依存関係を取得してくださいこれらのJARおよびディレクトリからURLClassLoaderを構築します。確信のgenerateTestClasspath() methodが出発点として役立ちます。

別のオプションは、別のプロジェクトでRealMessageクラスをコンパイルし、別のJARをビルドし、それをメッセージプラグインへの依存として含めることです。 message-plugin-additionsプロジェクトはmessage.RealMessageクラスが含まれてい

<build> 
    <plugins> 
     <plugin> 
      <artifactId>message-plugin</artifactId> 
      <groupId>message-plugin</groupId> 
      <version>1.0</version> 
      <executions> 
       <execution> 
        <phase>test</phase> 
        <goals> 
         <goal>message</goal> 
        </goals> 
       </execution> 
      </executions> 
      <configuration> 
       <messageClass>message.RealMessage</messageClass> 
      </configuration> 
      <dependencies> 
       <groupId>message-plugin-additions</groupId> 
       <artifactId>message-plugin-additions</artifactId> 
       <version>1.0</version> 
      </dependencies> 
     </plugin> 
    </plugins> 
</build> 

:この場合

ビルドセクションには、次のようになります。別のプロジェクトを使用する場合、これは最初のオプションよりもずっと簡単に終わるでしょう。

+0

このエントリーをはてなブックマークに追加 –

1

新しいURLClassLoaderを構築して、現在のClassLoaderにチェーンしてみました。

@Override 
public void execute() throws MojoExecutionException, MojoFailureException { 
    //a direct absolute path just for testning 
    chainClassLoader(new File("C:\\Users\\admin\\.m2\\repository\\message-plugin\\real-message\\1.0\\real-message-1.0.jar")); 
    Message message = null; 

    try { 
     Class<?> clazz = Class.forName(messageClass); 
     message = (Message) clazz.newInstance(); 
    } catch (Exception e) { 
     getLog().error(e); 
    } 

    getLog().info(message.getMessage()); 
} 

private void chainClassLoader(File file) throws Exception { 
     ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); 
     URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}, currentClassLoader); 
     Thread.currentThread().setContextClassLoader(urlClassLoader); 
} 

でも、私はClassNotFoundExceptionを取得します。

また、@requiresDependencyResolutionと「プロジェクトの依存関係をどのように取得するのですか?

EDIT:

は、[OK]を私はそれを得たと思います。プラグインのClassLoader階層は次のようになります。

null 
    sun.misc.Launcher$ExtClassLoader 
    sun.misc.Launcher$AppClassLoader 

null 
    org.codehaus.classworlds.RealmClassLoader 
    java.net.URLClassLoader // my chained classloader 

Class.forName(clazz)た彼の親ExtClassLoaderに委譲することをAppClassLoaderから始めることによってclazzを見つけようとします。しかし、別のClassLoader階層にあるURLClassLoaderに新しいクラスパスを追加したので、ClassNotFoundExceptionが得られます。

スレッドのContextClassLoaderURLClassLoaderをチェーンしているので、解決策はClass.forName(clazz)ではなく、Thread.currentThread().getContextClassLoader().loadClass(clazz)を使用することです。

関連する問題