Esta classe Java verifica o conteúdo de todos os conteúdos WAR e JARs encontrados na lista de diretórios e imprime um resumo das versões do arquivo de classe java para cada componente, incluindo cada JAR dentro dos WARs:
public class ShowClassVersions {
private static final byte[] CLASS_MAGIC = new byte[] {(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe};
private final byte[] bytes = new byte[8];
private TreeMap<String,ArrayList<String>> vers = new TreeMap<>();
private void scan(Path f) throws IOException {
if (Files.isDirectory(f)) {
Pattern pattern = Pattern.compile("\\.[wj]ar$"); // or |\\.class
try(var stream = Files.find(f, Integer.MAX_VALUE, (p,a) -> a.isRegularFile() && pattern.matcher(p.toString()).find())) {
stream.forEach(this::scanFile);
}
return;
}
scanFile(f);
}
private void scanFile(Path f) {
String fn = f.getFileName().toString();
try {
if (fn.endsWith(".jar"))
scanArchive(f);
else if (fn.endsWith(".war"))
scanArchive(f);
else if (fn.endsWith(".class"))
record(f, versionOfClass(f));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void scanArchive(Path p) throws IOException {
try(InputStream in = Files.newInputStream(p)) {
scanArchive(p.toAbsolutePath().toString(), in);
}
}
private String scanArchive(String desc, InputStream in) throws IOException {
String version = null;
ZipInputStream zip = new ZipInputStream(in);
ZipEntry entry = null;
while ((entry = zip.getNextEntry()) != null) {
String name = entry.getName();
if (version == null && name.endsWith(".class")) {
version = versionOfClass(zip);
}
else if (name.endsWith(".jar")) {
scanArchive(desc+" ==>> "+name, zip);
}
}
if (version != null)
record(desc, version);
return version;
}
private String versionOfClass(Path p) throws IOException {
String version = null;
try(InputStream in = Files.newInputStream(p)) {
version = versionOfClass(in);
}
return version;
}
private 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;
}
private void record(String p, String v) {
vers.computeIfAbsent(String.valueOf(v), k -> new ArrayList<String>()).add(p);
}
private void record(Path p, String v) {
record(p.toAbsolutePath().toString(), v);
}
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);
}
};
}
}