Upgrading will tell you, with some testing. If you have a system of 800+ modules you should consider addressing your standardisation issues before you upgrade - try to use same versions of your dependencies - such as JDBC drivers, logging jars etc, and same for your developer build environments so everyone can make the same step together - and therefore rollback together if it fails at some stage.
This class will dump out versions of all .class and .jar files it sees in any directories or files it scans. It may help. Or not.
public class ShowClassVersions implements FileVisitor<Path> {
private static final byte[] CLASS_MAGIC = new byte[] {(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe};
private static final byte[] bytes = new byte[8];
private TreeMap<String,ArrayList<Path>> vers = new TreeMap<>();
ShowClassVersions() {
}
private void scan(Path f) throws IOException {
if (Files.isDirectory(f)) {
Files.walkFileTree(f, this);
return;
}
record(f);
}
private static String versionOfFile(Path f) throws IOException {
String fn = f.getFileName().toString();
if (fn.endsWith(".class"))
return String.valueOf(versionOfClass(f));
if (fn.endsWith(".jar"))
return String.valueOf(versionOfJar(f));
return null;
}
public static String versionOfClass(Path p) throws IOException {
String version = null;
try(InputStream in = Files.newInputStream(p)) {
version = versionOfClass(in);
}
return version;
}
public static String versionOfClass(InputStream in) throws IOException {
String version = null;
int c = in.read(bytes);
if (c == bytes.length && Arrays.mismatch(bytes, CLASS_MAGIC) == CLASS_MAGIC.length) {
int minorVersion = (bytes[4] << 8) + (bytes[4] << 0);
int majorVersion = (bytes[6] << 8) + (bytes[7] << 0);
version = ""+majorVersion + "." + minorVersion;
}
return version;
}
public static String versionOfJar(Path p) throws IOException {
String version = null;
try(ZipInputStream in = new ZipInputStream(Files.newInputStream(p))) {
ZipEntry entry = null;
while (version == null && (entry = in.getNextEntry()) != null) {
if (entry.getName().endsWith(".class") /* && entry.getSize() > bytes.length */) {
version = versionOfClass(in);
}
}
}
return version;
}
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
record(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
void record(Path p) throws IOException {
String v = versionOfFile(p);
if (v != null) {
vers.computeIfAbsent(v, k -> new ArrayList<Path>()).add(p);
}
}
public static void main(String[] args) throws IOException {
ShowClassVersions v = new ShowClassVersions();
var files = Arrays.stream(args).map(Path::of).collect(Collectors.toList());
for (var f : files) {
v.scan(f);
}
for (var ver : v.vers.keySet()) {
System.out.println("Version: "+ver);
for (var p : v.vers.get(ver)) {
System.out.println(" "+p);
}
};
}
}