我有一个包含多个模块的 Maven 项目,即
<module>backend</module> <!-- provides annotations -->
<module>annotationProcessor</module> <!-- processes ann., generates files -->
<module>mainprog</module> <!-- uses annotations/files -->
backend
提供注解类 MyAnnotation
用于注释类。
mainprog
包含 Mainprog.java
定义了一个带有 @MyAnnotation
的类注解。在运行时,此类尝试通过 getResourceAsStream("Mainprog.properties")
加载文件(尚不存在)。
annotationProcessor
有一个类 MyAnnotationProcessor
maven 执行并找到我的注释。
处理器应该创建文件Mainprog.properties
来自注释处理器收集的信息。
我无法设法将属性文件放在执行/测试 Mainprog 时可以找到的地方。
- 在 Maven 工作流中,我应该将文件生成到哪里?
- 如何告诉 maven 这个文件是在测试中使用还是在运行时使用?最终 必须打包在 jar 里。
主程序
package demo;
@MyAnnotation
public class Mainprog {
}
使用属性文件
目前我是在测试课上做的,但以后会在类里面做。
package demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.junit.Test;
public class MainprogTest {
Class testclass = Mainprog.class;
@Test
public void testPropertiesFile() throws IOException {
String fn = testclass.getCanonicalName().replace('.', '/') + ".properties";
System.err.println("loading: '"+fn+"'");
InputStream in = getClass().getResourceAsStream(fn);
Properties prop = new Properties();
prop.load(in);
in.close();
}
}
这目前是这样运行的:
loading: 'demo/Mainprog.properties'
Tests in error:
testPropertiesFile(demo.MainprogTest)
带有 NullPointerException
,因为流返回 null
,即不存在。
尽管文件在那里(但它在正确的位置吗?):
towi@havaloc:~/git/project/mainprog$ find . -name Mainprog.properties
./src/java/demo/Mainprog.properties
./target/classes/demo/Mainprog.properties
处理器
package demo;
import com.github.javaparser.*;
import com.github.javaparser.ast.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
@SupportedAnnotationTypes({"demo.MyAnnotation"})
public class MyAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
for (TypeElement te : elements) {
for (Element e : env.getElementsAnnotatedWith(te))
{
processAnnotation(e);
}
}
return true;
}
private void processAnnotation(Element elem) {
final TypeElement classElem = (TypeElement) elem;
...
final String prefix = System.getProperty("user.dir").endsWith("/"+"mainprog") ? "." : "mainprog";
final String className = classElem.getQualifiedName().toString();
String fileName = prefix + "/src/java/" + className.replace('.', '/') + ".java";
FileInputStream in = new FileInputStream(fileName);
final CompilationUnit cu = JavaParser.parse(in);
final CallGraph graph = ...
generateInfoProperties(classElem, fileName, graph);
}
private void generateInfoProperties(TypeElement classElem, String inFilename, CallGraph graph) throws IOException {
final File outFile = new File(inFilename
.replace("/src/java/", "/src/java/") // <<< WHERE TO ???
.replace(".java", ".properties"));
outFile.getParentFile().mkdirs();
try (PrintWriter writer = new PrintWriter(outFile, "UTF-8")) {
final Properties ps = new Properties();
graph.storeAsProperties(ps);
ps.store(writer, inFilename);
writer.close();
}
}
}
如您所见,在处理目录名称时会进行大量猜测和“启发式”操作。所有这些System.getProperty("user.dir")
和 replace("/src/java/", "/src/java/")
可能是错误的,但什么更好?
maven
当然,在 Maven 中我有 4 个 pom
-
pom.xml
-
backend/pom.xml
-
annotationProcessor/pom.xml
-
mainprog/pom.xml
在我看来,只有一个包含任何值得注意的内容,即 mainprog/pom.xml
中注释处理器的执行。 :
<project>
....
<dependencies>
<dependency>
<groupId>project</groupId>
<artifactId>backend</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>project</groupId>
<artifactId>annotationProcessor</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>mainprog</finalName>
<sourceDirectory>src/java</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src/conf</directory>
<targetPath>META-INF</targetPath>
</resource>
<resource>
<directory>${basedir}/web</directory>
</resource>
<resource>
<directory>${basedir}/src/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
<include>**/*.wsdl</include>
<include>**/*.xsd</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessors>
<annotationProcessor>demo.MyAnnotationProcessor
</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
我想通过生成文件到 /src/java/
然后有 <resource><directory>${basedir}/src/java
和 <include>**/*.properties
足够了,但似乎还不够。这是为什么?
最佳答案
使用提供的 Filer
,可以使用 processingEnv.getFiler()
获取。如果您使用它创建源文件,编译器将在下一轮编译它,您无需担心配置 Maven 来编译生成的源文件。
关于java - 在 Maven 工作流中的注释处理期间在哪里生成资源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33392389/