View Javadoc
1   package org.codehaus.plexus.languages.java.version;
2   
3   import java.io.IOException;
4   import java.io.UncheckedIOException;
5   import java.nio.file.Files;
6   import java.nio.file.Path;
7   
8   /*
9    * Licensed to the Apache Software Foundation (ASF) under one
10   * or more contributor license agreements.  See the NOTICE file
11   * distributed with this work for additional information
12   * regarding copyright ownership.  The ASF licenses this file
13   * to you under the Apache License, Version 2.0 (the
14   * "License"); you may not use this file except in compliance
15   * with the License.  You may obtain a copy of the License at
16   *
17   *   http://www.apache.org/licenses/LICENSE-2.0
18   *
19   * Unless required by applicable law or agreed to in writing,
20   * software distributed under the License is distributed on an
21   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22   * KIND, either express or implied.  See the License for the
23   * specific language governing permissions and limitations
24   * under the License.
25   */
26  
27  /**
28   * Reads the bytecode of a Java class to detect the major, minor and Java
29   * version that was compiled.
30   *
31   * @author Jorge Solórzano
32   */
33  public final class JavaClassfileVersion {
34  
35      private final int major;
36      private final int minor;
37  
38      JavaClassfileVersion(int major, int minor) {
39          if (major < 45) {
40              throw new IllegalArgumentException("Java class major version must be 45 or above.");
41          }
42          this.major = major;
43          this.minor = minor;
44      }
45  
46      /**
47       * Reads the bytecode of a Java class file and returns the
48       * {@link JavaClassfileVersion}.
49       *
50       * @param bytes {@code byte[]} of the Java class file
51       * @return the {@link JavaClassfileVersion} of the byte array
52       */
53      public static JavaClassfileVersion of(byte[] bytes) {
54          return JavaClassfileVersionParser.of(bytes);
55      }
56  
57      /**
58       * Reads the bytecode of a Java class file and returns the
59       * {@link JavaClassfileVersion}.
60       *
61       * @param path {@link Path} of the Java class file
62       * @return the {@link JavaClassfileVersion} of the path java class
63       */
64      public static JavaClassfileVersion of(Path path) {
65          try {
66              byte[] readAllBytes = Files.readAllBytes(path);
67              return of(readAllBytes);
68          } catch (IOException ex) {
69              throw new UncheckedIOException(ex);
70          }
71      }
72  
73      /**
74       * JavaVersion of the class file version detected.
75       *
76       * @return JavaVersion based on the major version of the class file.
77       */
78      public JavaVersion javaVersion() {
79          int javaVer = major - 44;
80          String javaVersion = javaVer < 9 ? "1." + javaVer : Integer.toString(javaVer);
81  
82          return JavaVersion.parse(javaVersion);
83      }
84  
85      /**
86       * Returns the major version of the parsed classfile.
87       *
88       * @return the major classfile version
89       */
90      public int majorVersion() {
91          return major;
92      }
93  
94      /**
95       * Returns the minor version of the parsed classfile.
96       *
97       * @return the minor classfile version
98       */
99      public int minorVersion() {
100         return minor;
101     }
102 
103     /**
104      * Returns if the classfile use preview features.
105      *
106      * @return {@code true} if the classfile use preview features.
107      */
108     public boolean isPreview() {
109         return minor == 65535;
110     }
111 
112     /**
113      * Returns a String representation of the Java class file version, e.g.
114      * {@code 65.0 (Java 21)}.
115      *
116      * @return String representation of the Java class file version
117      */
118     @Override
119     public String toString() {
120         return major + "." + minor + " (Java " + javaVersion() + ")";
121     }
122 
123     @Override
124     public int hashCode() {
125         final int prime = 31;
126         int result = 1;
127         result = prime * result + major;
128         result = prime * result + minor;
129         return result;
130     }
131 
132     @Override
133     public boolean equals(Object obj) {
134         if (this == obj) return true;
135         if (!(obj instanceof JavaClassfileVersion)) return false;
136         JavaClassfileVersion other = (JavaClassfileVersion) obj;
137         if (major != other.major) return false;
138         if (minor != other.minor) return false;
139         return true;
140     }
141 }