2017-02-21 2 views
14

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

UPDATE: Я уже пытался ставить сгенерированные классы непосредственно в target/classes т.е. project.build.outputDirectory, в начале Maven сборки Lifecycle, но мне кажется, что не стоит на пути к классу. Сгенерированные типы не могут быть разрешены плагином Maven Compiler или IDE. Я также попытался использовать плагин Build Helper Maven для добавления дополнительного каталога ресурсов под target, содержащего сгенерированные классы, которые затем автоматически копировались в target/classes. Эта конфигурация показала ту же проблему.

UPDATE: Я создал полный публичный репозиторий на 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 { 
} 

сеть/bytebuddy/тест/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.

+0

Возможно, вы можете посмотреть исходный код jax-b: xjc, он делает simil ar thing на этапе генерации-источников – HRgiger

ответ

1

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

+0

Я попытался помещать классы там, в начале жизненного цикла сборки Maven, но кажется, что 'target/classes' (' project.build.outputDirectory') не находится в пути к классу. Сгенерированные типы не могут быть разрешены с помощью Maven Compiler Plugin или IDE. –

+1

@Mark Они находятся на пути к классу. На каком этапе вы создали их в «target/classes»? Вы уверены, что они созданы с правильной структурой пакета? Вы _see_ затем генерировались в журналах или в этой папке? – Tunaki

+0

@Tunaki Я извлекаю неусовершенствованные классы для 'target/classes' в фазе' generate-resources'. Я улучшаю классы в фазе «процессы-ресурсы». И ты прав. Запуск Maven с '--debug' показал, что' classpathElements' включает 'target/classes'. С моей текущей конфигурацией я могу получить Maven для компиляции статического класса, который ссылается на сгенерированный тип, который существует в 'target/classes', и я вижу, что класс верен, но IDE (IntelliJ и Eclipse) не похоже, распознают сгенерированный класс и сообщают об ошибках исходного уровня (не удается разрешить символ) в статическом типе. –

4

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

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

+0

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

1

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

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

Как почему это похоже на работу:

Когда Иды генерировать их конфигурации проекта/модуль, основанный на файлах 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> 
Смежные вопросы