Most Used Method Out There
What java method is referenced by the most classes in the most popular JARs I can find in the maven repository? Here’s the program.
package io.github.math_ias;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.InvalidPathException;
import java.lang.classfile.ClassFile;
import java.lang.classfile.ClassModel;
import java.lang.classfile.MethodModel;
import java.lang.classfile.constantpool.PoolEntry;
import java.lang.classfile.constantpool.ClassEntry;
import java.lang.classfile.constantpool.MethodRefEntry;
import java.lang.classfile.constantpool.InterfaceMethodRefEntry;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentHashMap;
/**
* Compile like ...
* javac --enable-preview -source 23 src/io/github/math_ias/MyCounter.java -d target
*/
public class MyCounter {
static record ClassMethod(String clazz, String method) {}
static record ClassMethodCount(String clazz, String method, Integer count) {}
static Comparator<ClassMethodCount> CLASS_METHOD_COUNT_COMPARATOR =
Comparator.comparingInt(ClassMethodCount::count);
static void pushNewCount(ClassMethodCount classMethodCount, TreeSet<ClassMethodCount> set) {
set.add(classMethodCount);
if (set.size() > 5) {
set.pollFirst();
}
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Expected exactly 1 argument, the root directory.");
System.exit(-1);
}
Path rootPath = null;
try {
rootPath = Path.of(args[0]);
} catch (InvalidPathException ipe) {
System.err.println("Expected first arg to be a valid root path (does not parse).");
ipe.printStackTrace(System.err);
System.exit(-1);
}
if (!Files.exists(rootPath)) {
System.err.println("Expected first arg to be a valid root path (does not exist).");
System.exit(-1);
}
ConcurrentHashMap<ClassMethod, Integer> map = new ConcurrentHashMap();
try {
Files.walk(rootPath)
.parallel()
// This lambda is likely repeating work Files.walk already does,
// plus this file extension business is nasty,
// but I'm betting that I can beat xargs without optimizing it.
.filter((Path path) ->
!Files.isDirectory(path) &&
path.getFileName().toString().endsWith(".class")
)
.forEach((Path path) -> addMethodsToMap(
path
, map
));
} catch (IOException ioe) {
System.err.println("Unexpected error occurred while traversing file tree.");
ioe.printStackTrace();
System.exit(-1);
}
TreeSet<ClassMethodCount> sortedSet =
new TreeSet<ClassMethodCount>(CLASS_METHOD_COUNT_COMPARATOR);
map.entrySet().forEach((Map.Entry<ClassMethod, Integer> mapEntry) ->
pushNewCount(
new ClassMethodCount(
mapEntry.getKey().clazz()
, mapEntry.getKey().method()
, mapEntry.getValue()
)
, sortedSet
)
);
sortedSet.forEach((ClassMethodCount classMethodCount) ->
System.out.println(
String.format(
"%d %s.%s"
, classMethodCount.count()
, classMethodCount.clazz()
, classMethodCount.method()
)
)
);
System.exit(0);
}
static Integer mergeInts(Integer left, Integer right) { return left + right; }
public static void addMethodsToMap(
Path path
, ConcurrentHashMap<ClassMethod, Integer> map
) {
try {
ClassModel classModel =
ClassFile.of()
.parse(path);
Iterator<PoolEntry> iterator = classModel.constantPool().iterator();
while (iterator.hasNext()) {
PoolEntry poolEntry = iterator.next();
switch (poolEntry) {
case MethodRefEntry methodRefEntry:
map.merge(
new ClassMethod(
methodRefEntry.owner().name().stringValue()
, methodRefEntry.name().stringValue()
)
, 1
, MyCounter::mergeInts
);
break;
case InterfaceMethodRefEntry interfaceMethodRefEntry:
map.merge(
new ClassMethod(
interfaceMethodRefEntry.owner().name().stringValue()
, interfaceMethodRefEntry.name().stringValue()
)
, 1
, MyCounter::mergeInts
);
break;
default: // Do nothing.
}
}
} catch (IOException io) {
System.err.println(String.format("Failed to read path %s, skipping.", path.toString()));
io.printStackTrace(System.err);
}
}
}
% java --enable-preview io.github.math_ias.MyCounter ../../jars
1377 clojure/lang/IFn.invoke
1384 java/lang/StringBuilder.<init>
2312 clojure/lang/AFunction.<init>
2721 java/lang/StringBuilder.append
5916 java/lang/Object.<init>
Nice. The init method. And that total count matches what the other tool shows.
% java --enable-preview io.github.math_ias.MyMain jars java/lang/Object "<init>" "()V" | wc -l
5916