问题
我有一个使用 Spring @CacheEvict 注释和嵌入式 Spring 表达式语言的类。当我允许 Eclipse 自动编译此类时,一切正常。但是,当我使用 Ant 任务(通过 Eclipse 或从命令行)进行编译时,生成的 .class 文件不起作用,并抛出一个看起来像红鲱鱼的异常。
我的问题:如何配置 Ant 构建以便它生成工作的 .class 工件(以便其他开发人员可以构建我的项目而不需要 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/ 中)
- 操作系统:Windows 7 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.6 到 1.7.0_17):
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
此存根项目也可作为 ZIP 存档提供,包括支持 Spring 和 JUnit 的 JAR 文件: Minimal Eclipse Project
重现步骤
- 在 Eclipse 中打开“compilerDebug”项目。
- 允许 Eclipse 自动构建“示例”包中的类。执行 Project Clean/Build 或打开 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 字节。
其他观察
- 我尝试将compiler="org.eclipse.jdt.core.JDTCompilerAdapter"添加到“javac”任务中,以强制 Ant 使用 Eclipse 编译器,但在此更改后单元测试仍然失败。SampleAction.class 在这里是 696 字节。
- 如果我从 @CacheEvict 注释中删除条件,则单元测试会通过两个编译器。
- 将源/目标级别设置为 1.5 或 1.7 无效。
- 强制 Ant 任务“在与工作区相同的 JRE 中运行”无效。
- 下载独立的 Ant 发行版 (1.9.1) 并运行与 Eclipse 完全隔离的 Ant 构建没有任何效果。
- 用声明性 XML 配置(使用 aspectjtools)替换 @CacheEvict 注释无效。
提前感谢您帮助防止我不可避免的精神错乱进行故障排除。
更新
请参阅下面提供的答案。使用javac编译时, Ant 没有将调试模式显式设置为true。SpEL 要求在类文件中包含额外的调试信息,以便正确处理注释。将 debug 设置为 true 立即纠正了该问题。
<javac debug="true" [...] />