問題
Spring @CacheEvict アノテーションと組み込みの Spring Expression Language を使用するクラスがあります。このクラスを Eclipse で自動的にコンパイルできるようにすると、すべて正常に動作します。ただし、Ant タスクを使用して (Eclipse またはコマンド ラインから) コンパイルすると、結果の .class ファイルが機能せず、赤いニシンのように見える例外がスローされます。
私の質問: 動作する .class アーティファクトを生成するように Ant ビルドを構成するにはどうすればよいですか (これにより、他の開発者は Eclipse を必要とせずに私のプロジェクトをビルドできます)。Eclipse と Ant の構成は同じように見えますが、どこかでプロパティが欠落しているに違いありません。
バージョン
- Ant (Eclipse に同梱): org.apache.ant_1.8.3.v20120321-1730
- Eclipse: Juno サービス リリース 1、20120920-0800
- JDK: 1.7.0_17
- JUnit: 4.10 (プロジェクトの /lib/ 内)
- OS:Windows7 64ビット
- 春: 3.2.2
サポート ファイル
プロジェクトを前に出さずに問題を説明するのは難しいため、問題を再現するために必要な最小限のファイルにプロジェクトを要約しました。
/src/sample/SampleAction.java : @CacheEvict アノテーションと SpEL を使用したメソッドが含まれています。
package sample;
import org.springframework.cache.annotation.CacheEvict;
public class SampleAction {
@CacheEvict(value = "sampleCache", allEntries = true, condition = "#string.bytes != null")
public void triggerCache(String string) {
System.out.println("triggerCache(" + string + ")");
}
}
/src/sample/SampleActionTest.java : Eclipse 成果物では機能するが、Ant 成果物では失敗する単体テスト。
package sample;
import org.junit.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"application.xml"})
public class SampleActionTest {
@Autowired
private SampleAction sampleAction;
@Test
public void testCacheMethod() {
sampleAction.triggerCache("Definitely not a null string.");
}
}
/src/sample/application.xml : キャッシングとアクション クラスの Spring 定義ファイル。
<cache:annotation-driven />
<bean id="sampleAction" class="sample.SampleAction" />
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="sampleCache" />
</set>
</property>
</bean>
/.settings/org.eclipse.jdt.core.prefs : Eclipse コンパイラー設定 (1.7.0_17 経由の 1.6):
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
/build.xml : 失敗した単体テストをクリーンアップ、コンパイル、および実行する Ant ビルド。
<path id="classpath.main">
<fileset dir="lib" includes="*.jar" />
</path>
<path id="classpath.test">
<path refid="classpath.main" />
<pathelement location="output/classes" />
</path>
<target name="compileFailure" description="Cleans, compiles, and runs a unit test, which fails.">
<delete quiet="true" dir="output/classes" />
<mkdir dir="output/classes" />
<copy tofile="output/classes/sample/application.xml" file="src/sample/application.xml" />
<javac srcdir="src" destdir="output/classes"
classpathref="classpath.main" source="1.6" target="1.6" includeantruntime="false" />
<junit printsummary="yes">
<classpath refid="classpath.test" />
<formatter type="plain" usefile="false"/>
<test name="sample.SampleActionTest" outfile="result" />
</junit>
</target>
/lib/*.jar : サポートするライブラリ:
com.springsource.org.aopalliance-1.0.0.jar
commons-logging-1.1.3.jar
junit-4.10.jar
spring-aop-3.2.2.jar
spring-beans-3.2.2.jar
spring-context-3.2.2.jar
spring-context-support-3.2.2.jar
spring-core-3.2.2.jar
spring-expression-3.2.2.jar
spring-test-3.2.2.jar
このスタブ プロジェクトは、Spring および JUnit のサポート JAR ファイルを含む ZIP アーカイブとしても利用できます: Minimal Eclipse Project
再現する手順
- Eclipse で「compilerDebug」プロジェクトを開きます。
- Eclipse が「サンプル」パッケージ内のクラスを自動的にビルドできるようにします。プロジェクトのクリーン/ビルドを実行するか、Java ファイルを開き、空白を編集して再保存します。Eclipse でコンパイルすると、output/classes/sample/SampleAction.class は 911 バイトになります。
- 「SampleActionTest」を右クリックし、「Run As... JUnit Test」を選択します。テストは正常にパスします。
- Ant ビューで build.xml ファイルを開きます。「compileFailure」ターゲットを右クリックし、「Run As... Ant Build」を選択します。「EL1007E:(pos 0): Field or property 'bytes' cannot be found on null」スタック トレースでテストが失敗します。Ant でコンパイルすると、output/classes/sample/SampleAction.class は 694 バイトになります。
その他の観察
- Ant に強制的に Eclipse コンパイラーを使用させるために、 compiler="org.eclipse.jdt.core.JDTCompilerAdapter"を「javac」タスクに追加しようとしましたが、この変更後も単体テストは失敗します。ここでは、SampleAction.class は 696 バイトです。
- @CacheEvict アノテーションから条件を削除すると、両方のコンパイラで単体テストに合格します。
- ソース/ターゲット レベルを 1.5 または 1.7 に設定しても効果はありません。
- Ant タスクを「ワークスペースと同じ JRE で実行する」ように強制しても効果はありません。
- スタンドアロンの Ant ディストリビューション (1.9.1) をダウンロードして、Eclipse から完全に分離された Ant ビルドを実行しても効果はありません。
- @CacheEvict アノテーションを宣言的な XML 構成 (aspectjtools を使用) に置き換えても効果はありません。
私の避けられない狂気のトラブルシューティングを防ぐのを手伝ってくれて、前もって感謝します.
アップデート
以下の回答を参照してください。Ant は、 javacでコンパイルするときに、デバッグ モードを明示的にtrueに設定していませんでした。SpEL では、注釈を正しく処理するために、追加のデバッグ情報をクラス ファイルに含める必要があります。debug を true に設定すると、すぐに問題が修正されました。
<javac debug="true" [...] />