Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何为不同的Java版本(6、7、8)支持不同版本的主(和测试)源集_Java_Maven_Java 8_Conditional Compilation - Fatal编程技术网

如何为不同的Java版本(6、7、8)支持不同版本的主(和测试)源集

如何为不同的Java版本(6、7、8)支持不同版本的主(和测试)源集,java,maven,java-8,conditional-compilation,Java,Maven,Java 8,Conditional Compilation,我有一个Java库项目。我想实现、测试并可能发布该项目的几个版本,这些版本打算与不同的Java版本一起使用:6、7、8 最简单的方法就是复制粘贴项目并支持多个源代码树,但我希望避免这种情况,因为这很繁琐且容易出错 另一种可能的方法是考虑“基本”项目和几个Java版本特定的项目,具体取决于。版本差异非常小,但我不知道如何在类层次结构中反映这个技术开发问题 所以我在找 一种预编译器 和/或标准Maven选项 和/或Maven插件 这有助于从单个源代码树支持多个特定于Java版本的库版本,并且对库

我有一个Java库项目。我想实现、测试并可能发布该项目的几个版本,这些版本打算与不同的Java版本一起使用:6、7、8

最简单的方法就是复制粘贴项目并支持多个源代码树,但我希望避免这种情况,因为这很繁琐且容易出错

另一种可能的方法是考虑“基本”项目和几个Java版本特定的项目,具体取决于。版本差异非常小,但我不知道如何在类层次结构中反映这个技术开发问题

所以我在找

  • 一种预编译器
  • 和/或标准Maven选项
  • 和/或Maven插件

这有助于从单个源代码树支持多个特定于Java版本的库版本,并且对库用户透明。

代码中嵌入了一种方法:从log4j2源代码:

   //  JDK 1.1 doesn't support readResolve necessary for the assertion 
   if (!System.getProperty("java.version").startsWith("1.1.")) {
        assertTrue(obj == Level.INFO);
    }

您还可以根据java版本使用和设置变量来更改代码。尽管在调试困难的情况下,它将在尽可能少的地方执行此操作。或者至少在运行动态代码之前打印一个日志,以便知道哪个版本/实际行有问题。

您可以从单个pom.xml文件为每个Java版本(6、7、8)生成一个jar

所有相关工作都在魔咒中进行

诀窍是执行mojo 3次,每次都将结果文件写入不同的文件。这将导致编译器运行多次,每次使用不同的版本并生成一个适当命名的文件

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <executions>
        <execution>
            <id>compile-1.6</id>
            <goals>
                <id>compile</id>
            </goals>
            <phase>compile</phase>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
                <executable>${env.JAVA_HOME_6}/bin/javac</executable>
                <outputFileName>mylib-1.6.jar</outputFileName>
            </configuration>
<!-- START EDIT -->
            <dependencies>
                <dependency>
                    <groupId>com.mycompany</groupId>
                    <artifactId>ABC</artifactId>
                    <version>1.0</version>
                </dependency>
            </dependencies>
<!-- END EDIT -->
        </execution>
        <execution>
            <id>compile-1.7</id>
            <phase>compile</phase>
            <goals>
                <id>compile</id>
            </goals>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <executable>${env.JAVA_HOME_7}/bin/javac</executable>
                <outputFileName>mylib-1.7.jar</outputFileName>
            </configuration>
<!-- START EDIT -->
            <dependencies>
                <dependency>
                    <groupId>com.mycompany</groupId>
                    <artifactId>XYZ</artifactId>
                    <version>2.0</version>
                </dependency>
            </dependencies>
<!-- END EDIT -->
        </execution>

        <!-- one more execution for 1.8, elided to save space -->

    </executions>
</plugin>

org.apache.maven.plugins
maven编译器插件
3.1
编译-1.6
编译
编译
1.6
1.6
${env.JAVA\u HOME\u 6}/bin/javac
mylib-1.6.jar
com.mycompany
基础知识
1
编译-1.7
编译
编译
1.7
1.7
${env.JAVA\u HOME\u 7}/bin/javac
mylib-1.7.jar
com.mycompany
XYZ
2
希望有帮助

编辑

RE:每个运行针对不同源进行编译的附加要求

请参见上面对pom代码段的编辑

每次执行都可以定义自己的依赖项库列表


因此,JDK6构建依赖于ABC.jar,而JDK7依赖于XYZ.jar。

为什么不收集每个java版本中应该不同的方法,将它们包装在一个“实用程序”项目中,制作您自己的api供主代码调用,并在发布时添加您想要的实用程序jar

比如:

util-api.jar(主项目调用的方法)

util-1.6.jar(无论哪种实现适用,即使在无需执行任何操作的情况下,如果需要“无操作”)


我已经多次成功地解决了与您现在遇到的问题类似的问题。

通过为每个java版本创建单独的概要文件,您可以有条件地包括一些源目录。然后,您可以使用profile name运行maven,它将定义您希望使用哪个版本的源。在这种情况下,所有公共源都保留在
src/main/java
中,而依赖于java版本的文件则放在
/src/main/java-X.X目录中

<profiles>
    <profile>
        <id>java-6</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>build-helper-maven-plugin</artifactId>
                    <version>1.5</version>
                    <executions>
                        <execution>
                            <id>add-sources</id>
                            <phase>generate-sources</phase>
                            <goals>
                                <goal>add-source</goal>
                            </goals>
                            <configuration>
                                <sources>
                                    <source>${basedir}/src/main/java-1.6</source>
                                </sources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
    <profile>
        <id>java-7</id>
        (...)
                                    <source>${basedir}/src/main/java-1.7</source>
    </profile>
    <profile>
        <id>java-8</id>
        (...)
                                    <source>${basedir}/src/main/java-1.8</source>
    </profile>
</profiles>

对于这样的事情,我会

  • 将JVM版本相关文件移动到它们自己的包中
  • 或者,使用命名约定来标识特定于JVM版本的文件
  • 用于编译,而不是Maven。Ant使基于名称或位置排除源文件变得容易。您还可以使用Ant轻松创建多个目标
  • 如果库对所有JVM版本使用相同的API,我将为JVM特定的类创建接口,然后根据JVM版本在运行时实例化适当的实现
在决定迁移到基于基础的构建之前,从事这项工作的人员已经与这个问题搏斗了一段时间


查看了解更多信息。

您需要做的是定义一个基本API,然后将新版本的Java可用功能添加为额外方法(可以从原始API方法调用)。这允许API的基本完整性从旧实现到新实现保持不变

例如:

public void forEach(Consumer<T> c);
public void forEach(消费者c);
是您的原始API方法,其中Consumer是您的org.mylib.Consumer。在Java8中,您可以用它做两件事。可以保留旧实现并添加新方法作为该实现的方便方法,也可以添加新实现并添加调用新实现的defender方法。无论哪种方式,实现API的遗留代码都将保持有效

方便方法示例:

//无需更改旧的Java 6样式实现
公共场所(消费者c);
默认void forEach(java.util.function.Consumer c){
//您的消费者需要j.u.f.C.的构造函数
消费者myC=新消费者(c);
forEach(myC);
}
Defender方法示例:

//Consumer扩展了j.u.f.C,因此它更具体,将覆盖
默认的void forEach(使用者c){
//我们所需要调用的另一个方法就是显式转换
forEach((java.util.function.Consumer)c);
}
//这里是全新的Java8风格实现
公共void forEach(java.util.function.consumerc);
显然,对于Java7版本,您无法在接口上定义默认方法,因此您需要
<project>
  [...]
  <build>
    [...]
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>${my.java.version}</source>
          <target>${my.java.version}</target>
        </configuration>
      </plugin>
    </plugins>
    [...]
  </build>
  [...]
</project>
public void forEach(Consumer<T> c);
// No need to change the old Java 6 style implementation
public void forEach(Consumer<T> c); 

default void forEach(java.util.function.Consumer<T> c){
    // Your Consumer needs a constructor for j.u.f.C
    Consumer<T> myC = new Consumer<T>(c);
    forEach(myC);
}
// Consumer extends j.u.f.C so this is more specific and will override
default void forEach(Consumer<T> c){ 
    // All we need to call the other method is an explicit cast
    forEach((java.util.function.Consumer<T>) c);
}

//All new Java 8 style implementation here
public void forEach(java.util.function.Consumer<T> c);
public interface MyConsumer<T> extends Consumer<T> {
    default void accept(T t){ // Formerly the abstract functional method
        getConsumer().accept(t);
    }
    public Consumer<T> getConsumer(); //Our new abstract functional method
}
public interface MyIterable<T> extends Iterable<T> {    
    default void each(MyConsumer<? super T> action){
        //Iterable.super.forEach((Consumer<? super T>) action);
        //
        // Or whatever else we need to do for our special
        // class processing
    }       
    default void each(Consumer<? super T> action){
        if (action instanceof MyConsumer){
            each((MyConsumer<? super T>) action);
        } else {
            Iterable.super.forEach(action);
        }
    }
    @Override
    default void forEach(Consumer<? super T> action){
        each(action);   
    }
}
api.each(()->System.out::println);
api.each(System.out::println);