简体   繁体   中英

Why does Groovy compiler apparently produce 1.5 version of Java?

After some problems with differences between JSE versions, I'm trying to log the Java compiler version used to compile (it's Groovy 2.1.9, Grails 2.3.8, Java 1.7.0_60 in fact).

After some rummaging around, I've constructed this piece of code to read the leading bytes of the class - see / http://en.wikipedia.org/wiki/Java_class_file#General_layout

(change the path to the class to match the package name):

class CompilerVersionSupport {

  public static String getVersion() {
    String classAsPath = 'com/my/organisation/CompilerVersionSupport.class';
    InputStream stream = (new CompilerVersionSupport()).getClass().getClassLoader().getResourceAsStream(classAsPath);
    DataInputStream ins = new DataInputStream (stream)

    assert( ins.readUnsignedShort() == 0xcafe )    
    assert( ins.readUnsignedShort() == 0xbabe )
    int minor = ins.readUnsignedShort();
    int major = ins.readUnsignedShort();
    ins.close();
    int javaVersion = major - 44 
    return "1.$javaVersion"
    }     
}

Trouble is, it returns 1.5.

What could be going on?

  • Charles

The default Groovy behaviour is not to compile the code with the same bytecode version as the JDK being used. 1.5 is the default for compatibility reasons, IMHO. If you want the compiler to output newer bytecode you need to set that explicitly.

For example if you're using Maven to compile the code, you can use the GMavenPlus plugin. See the description of the targetBytecode parameter.

If you're not using Maven you can use -Dgroovy.target.bytecode=1.7 or research the possibilities for your particular build tool

If you're using Maven as the build tool, then chances are that it's using the gmavenplus-plugin to compile Groovy. To find out the target Java version of the bytecode generated I poked into the pom of the gmavenplus-plugin that my application uses: ~/.m2/repository/org/codehaus/gmavenplus/gmavenplus-plugin/1.5/gmavenplus-plugin-1.5.pom .

Inside that file I saw this, notice <javaVersion/> ,

 <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <mavenVersion>2.2.1</mavenVersion>
    <coberturaPluginVersion>2.7</coberturaPluginVersion>
    <javadocPluginVersion>2.10.1</javadocPluginVersion>
    <!-- these are properties so integration tests can use them -->
    <javaVersion>1.5</javaVersion>
    <dependencyPluginVersion>2.10</dependencyPluginVersion>
    <compilerPluginVersion>3.2</compilerPluginVersion>
    <junitVersion>4.12</junitVersion>
    <surefirePluginVersion>2.18.1</surefirePluginVersion>
    <pluginPluginVersion>3.4</pluginPluginVersion>
    <!-- this is a property so that site generation can use it -->
    <sourcePluginVersion>2.4</sourcePluginVersion>
    <!-- this is a property so that site generation and integration tests can use it -->
    <groovyVersion>2.4.1</groovyVersion>
  </properties>
...
<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${compilerPluginVersion}</version>
        <configuration>
          <source>${javaVersion}</source>
          <target>${javaVersion}</target>
        </configuration>
      </plugin>

I use IntelliJ for an IDE. IntelliJ is automatically setting the language level to Java 1.5. Even if I change it, when I re-import projects it resets back to Java 1.5 (I've fuzzed out sensitive information),

在此处输入图片说明

I think the issue is with the program you are using to find the class version. If the assertion is not enabled the stream doesnt read the first two unsigned shorts and hence the subsequent minor and major read statements results in 0Xcafe and 0xbabe respectively. Try enabling assertion or try using an if check.

public static String getVersion() throws Exception {
    String classAsPath = "com/my/organisation/CompilerVersionSupport.class";
    InputStream stream = (new CompilerVersionSupport()).getClass().getClassLoader().getResourceAsStream(classAsPath);
    DataInputStream ins = new DataInputStream(stream);

    if(ins.readUnsignedShort() != 0xcafe) throw new AssertionError("Invalid Class");
    if(ins.readUnsignedShort() != 0xbabe) throw new AssertionError("Invalid Class");
    int minor = ins.readUnsignedShort();
    int major = ins.readUnsignedShort();
    ins.close();
    int javaVersion = major - 44;
    return "1." + javaVersion;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM