Могу ли я динамически генерировать и ссылаться на класс в исходном файле в том же проекте Maven?

В Maven Build я динамически генерирую некоторые типы Java, используя библиотеку генерации байтового кода (Byte Buddy). Естественно, эти файлы классов не имеют соответствующих исходных файлов. Таким образом будет создано только несколько классов. Большая часть кода для этого проекта будет источником Java. В идеале, источник Java будет ссылаться на сгенерированные типы статическим способом, а не на использование генерации кода отражения или времени выполнения, что означает, что классы должны находиться в пути класса компиляции для javac. Могу ли я получить сгенерированные классы в пути класса компиляции для одного и того же проекта Maven, т.е. Без отдельного проекта Maven и артефакта для хранения сгенерированного байтового кода, на который ссылается проект Maven, содержащий исходный код?

ОБНОВЛЕНИЕ: Я уже пробовал сгенерировать сгенерированные классы непосредственно в target/classes i.e. project.build.outputDirectory, в начале жизненного цикла сборки Maven, но, похоже, это не на пути к классу. Сгенерированные типы не могут быть разрешены с помощью Плагина компилятора Maven или IDE. Я также попытался использовать плагин Build Helper Maven, чтобы добавить дополнительный каталог ресурсов в target, содержащий сгенерированные классы, которые затем автоматически копировались в target/classes. Эта конфигурация показала ту же проблему.

ОБНОВЛЕНИЕ: Я создал полное публичное репо на GitHub: https://github.com/mches/so-42376851

Вот Maven POM для проекта. Я хочу иметь статические классы, которые ссылаются на расширенные классы байт кода:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>demo</groupId>
        <artifactId>demo</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <artifactId>demo-enhanced</artifactId>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>demo</groupId>
                                    <artifactId>demo-original</artifactId>
                                    <version>${project.version}</version>
                                    <overWrite>true</overWrite>
                                    <outputDirectory>${project.build.outputDirectory}</outputDirectory>
                                    <includes>**/*.class</includes>
                                    <excludes>META-INF/</excludes>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>net.bytebuddy</groupId>
                <artifactId>byte-buddy-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>transform</goal>
                        </goals>
                        <configuration>
                            <initialization>
                                <entryPoint>net.bytebuddy.test.SimpleEntryPoint</entryPoint>
                                <groupId>demo</groupId>
                                <artifactId>demo-transformer</artifactId>
                            </initialization>
                            <transformations>
                                <transformation>
                                    <plugin>net.bytebuddy.test.SimplePlugin</plugin>
                                    <groupId>demo</groupId>
                                    <artifactId>demo-transformer</artifactId>
                                </transformation>
                            </transformations>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

и вот родительский POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>demo</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>demo-original</module>
        <module>demo-transformer</module>
        <module>demo-enhanced</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <byte-buddy.version>1.6.9</byte-buddy.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>net.bytebuddy</groupId>
                <artifactId>byte-buddy</artifactId>
                <version>${byte-buddy.version}</version>
            </dependency>
            <dependency>
                <groupId>demo</groupId>
                <artifactId>demo-original</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>demo</groupId>
                <artifactId>demo-transformer</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>demo</groupId>
                <artifactId>demo-enhanced</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>net.bytebuddy</groupId>
                    <artifactId>byte-buddy-maven-plugin</artifactId>
                    <version>${byte-buddy.version}</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

foo/Bar.java(исходный источник):

package foo;

public class Bar {
}

net/bytebuddy/test/SimplePlugin.java(усилитель байтового кода):

package net.bytebuddy.test;

import net.bytebuddy.build.Plugin;
import net.bytebuddy.description.modifier.Visibility;


import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;

public class SimplePlugin implements Plugin {
    @Override
    public boolean matches(TypeDescription target) {
        return target.getName().equals("foo.Bar");
    }

    @Override
    public DynamicType.Builder<?> apply(DynamicType.Builder<?> builder, TypeDescription typeDescription) {
        if (typeDescription.getTypeName().equals("foo.Bar")) {
            builder = builder.defineField("qux", String.class, Visibility.PRIVATE)
                    .defineMethod("getQux", String.class, Visibility.PUBLIC)
                    .intercept(FieldAccessor.ofField("qux"))
                    .defineMethod("setQux", void.class, Visibility.PUBLIC)
                    .withParameter(String.class)
                    .intercept(FieldAccessor.ofField("qux"));
        }
        return builder;
    }
}

foo/Baz.java(статический исходный файл, ссылающийся на динамический тип):

package foo;

public class Baz {
    private Bar bar = new Bar();

    public String getQuux() {
        return bar.getQux();
    }

    public void setQuux(String quux) {
        bar.setQux(quux);
    }
}

UPDATE: Кажется, что Maven понимает структуру с объединенным модулем с расширенным байтовым кодом и исходным кодом статического класса, а также отдельными модулями для каждого, но IDE, IntelliJ и Eclipse не понимают путь класса для любой структуры, как это делает Maven.

Ответы

Ответ 1

С Byte Buddy вы генерируете файлы классов, а не исходные файлы. К сожалению, Maven знает только о сгенерированных источниках, но не о сгенерированных файлах классов. Поэтому проще всего создать конкретный модуль.

Если это невозможно, вы можете скопировать их в любую исходную папку вашего проекта Maven, например resources. Некоторые IDE находят эти классы и обрабатывают их, только если они были у вас в папке java, но не пытались скомпилировать их, так как файлы заканчиваются на .class.

Ответ 2

Да, вы можете. Создайте свои классы на фазе предварительного компиляции и поместите их в папку целевых/классов.

Ответ 3

Это не мое идеальное решение, но идея, которая, кажется, работает, заключается в двух компромиссах:

  • Используйте отдельные модули Maven для расширенного байтового кода и статических классов.
  • Не создавайте усовершенствованный модуль байтового кода в том же сборке реактора Maven, что и модуль статических классов.

Как это работает:

Когда среда IDE генерирует свою конфигурацию проекта/модуля на основе файлов Maven pom.xml, они будут зависеть от расширенного байтового кода как библиотеки /JAR, а не от проекта/модуля. JAR заканчивается на пути класса IDE для модуля статических классов, и расширенные классы разрешаются.

Файл проекта IntelliJ для расширенного модуля байтового кода:

<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
    <output url="file://$MODULE_DIR$/target/classes" />
    <output-test url="file://$MODULE_DIR$/target/test-classes" />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
      <excludeFolder url="file://$MODULE_DIR$/target" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>

Файл проекта IntelliJ с модулями Maven в отдельных сборках (ошибках):

<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
    <output url="file://$MODULE_DIR$/target/classes" />
    <output-test url="file://$MODULE_DIR$/target/test-classes" />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
      <excludeFolder url="file://$MODULE_DIR$/target" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="module" module-name="demo-enhanced" />
  </component>
</module>

Файл проекта IntelliJ с модулями Maven в одной и той же сборке (без ошибок):

<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
    <output url="file://$MODULE_DIR$/target/classes" />
    <output-test url="file://$MODULE_DIR$/target/test-classes" />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
      <excludeFolder url="file://$MODULE_DIR$/target" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="library" name="Maven: demo:demo-enhanced:1.0-SNAPSHOT" level="project" />
  </component>
</module>