java - 在 Maven 工作流中的注释处理期间在哪里生成资源?

标签 java maven annotation-processing

我有一个包含多个模块的 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/

相关文章:

kotlin - 将 Kotlin 与生成的 Java 类集成

java - 使用 HashMap 值从 TreeSet 中删除对象

java - hashCode() 是否在任何地方使用?

maven - Jenkins & Sonar : [ERROR] Unable to evict preview database:/batch_bootstrap/evict? 项目=68

java.lang.NoClassDefFoundError : org/springframework/web/util/UriTemplateHandler 错误

javax.lang.模型 : How do I get the type of a field?

java - Android中通过socket连接到服务器

java - 如何在 Swing JTextArea 中打开任何 PDF 和 Word 文件?

java - SAX 解析异常 : maven jaxb2 plugin seems not to import schemas correctly

Java 6 注解处理——从注解中获取类