Skip to content

Instantly share code, notes, and snippets.

@thomasdarimont
Last active September 8, 2023 22:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save thomasdarimont/1d91117aca91be5b6e8151388d671c66 to your computer and use it in GitHub Desktop.
Save thomasdarimont/1d91117aca91be5b6e8151388d671c66 to your computer and use it in GitHub Desktop.
Small tool to find classes with executable main methods in a given JDK.

Executable main classes in JDK 21

java -DshowCommand=true --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED MainMethodFinder.java

Output (JDK 21)

openjdk 21-ea 2023-09-19
OpenJDK Runtime Environment (build 21-ea+27-2343)
OpenJDK 64-Bit Server VM (build 21-ea+27-2343, mixed mode, sharing)
java -m java.base/java.lang.foreign.snippets.Snippets$ArenaSnippets
java -m java.base/java.util.regex.PrintPattern
java -m java.base/jdk.internal.org.objectweb.asm.util.ASMifier
java -m java.base/jdk.internal.org.objectweb.asm.util.CheckClassAdapter
java -m java.base/jdk.internal.org.objectweb.asm.util.Textifier
java -m java.base/sun.launcher.LauncherHelper$FXHelper
java -m java.base/sun.security.provider.PolicyParser
java -m java.base/sun.security.tools.keytool.Main
java -m java.desktop/sun.java2d.loops.GraphicsPrimitiveMgr
java -m java.prefs/java.util.prefs.Base64
java -m java.rmi/sun.rmi.registry.RegistryImpl
java -m java.scripting/com.sun.tools.script.shell.Main
java -m java.xml/com.sun.org.apache.xalan.internal.xsltc.ProcessorVersion
java -m java.xml/com.sun.org.apache.xerces.internal.impl.Constants
java -m java.xml/com.sun.org.apache.xerces.internal.impl.xpath.XPath
java -m java.xml/com.sun.org.apache.xerces.internal.impl.xpath.regex.REUtil
java -m jdk.compiler/com.sun.tools.javac.Main
java -m jdk.compiler/com.sun.tools.javac.launcher.Main
java -m jdk.compiler/sun.tools.serialver.SerialVer
java -m jdk.hotspot.agent/com.sun.java.swing.ui.TabsDlg
java -m jdk.hotspot.agent/com.sun.java.swing.ui.WizardDlg
java -m jdk.hotspot.agent/sun.jvm.hotspot.CLHSDB
java -m jdk.hotspot.agent/sun.jvm.hotspot.DebugServer
java -m jdk.hotspot.agent/sun.jvm.hotspot.HSDB
java -m jdk.hotspot.agent/sun.jvm.hotspot.HelloWorld
java -m jdk.hotspot.agent/sun.jvm.hotspot.ObjectHistogram
java -m jdk.hotspot.agent/sun.jvm.hotspot.SALauncher
java -m jdk.hotspot.agent/sun.jvm.hotspot.StackTrace
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.bsd.BsdAddress
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.dummy.DummyAddress
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.linux.LinuxAddress
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.posix.elf.ELFFileParser
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.remote.RemoteAddress
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.win32.coff.DumpExports
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.win32.coff.TestDebugInfo
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.win32.coff.TestParser
java -m jdk.hotspot.agent/sun.jvm.hotspot.debugger.windbg.WindbgAddress
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.ClassLoaderStats
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.FinalizerInfo
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.FlagDumper
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.HeapDumper
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.HeapSummary
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.JInfo
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.JMap
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.JSnap
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.JStack
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.ObjectHistogram
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.PMap
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.PStack
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.StackTrace
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.SysPropsDumper
java -m jdk.hotspot.agent/sun.jvm.hotspot.tools.jcore.ClassDump
java -m jdk.hotspot.agent/sun.jvm.hotspot.ui.AnnotatedMemoryPanel
java -m jdk.hotspot.agent/sun.jvm.hotspot.ui.CommandProcessorPanel
java -m jdk.hotspot.agent/sun.jvm.hotspot.ui.DebuggerConsolePanel
java -m jdk.hotspot.agent/sun.jvm.hotspot.ui.HighPrecisionJScrollBar
java -m jdk.hotspot.agent/sun.jvm.hotspot.ui.ObjectHistogramPanel
java -m jdk.hotspot.agent/sun.jvm.hotspot.utilities.PlatformInfo
java -m jdk.hotspot.agent/sun.jvm.hotspot.utilities.RBTree
java -m jdk.httpserver/sun.net.httpserver.simpleserver.JWebServer
java -m jdk.httpserver/sun.net.httpserver.simpleserver.Main
java -m jdk.internal.le/jdk.internal.org.jline.terminal.impl.Diag
java -m jdk.jartool/sun.security.tools.jarsigner.Main
java -m jdk.jartool/sun.tools.jar.Main
java -m jdk.javadoc/jdk.javadoc.internal.doclint.DocLint
java -m jdk.javadoc/jdk.javadoc.internal.tool.Main
java -m jdk.jcmd/sun.tools.jcmd.JCmd
java -m jdk.jcmd/sun.tools.jinfo.JInfo
java -m jdk.jcmd/sun.tools.jmap.JMap
java -m jdk.jcmd/sun.tools.jps.Jps
java -m jdk.jcmd/sun.tools.jstack.JStack
java -m jdk.jcmd/sun.tools.jstat.Jstat
java -m jdk.jconsole/sun.tools.jconsole.JConsole
java -m jdk.jdeps/com.sun.tools.javap.Main
java -m jdk.jdeps/com.sun.tools.jdeprscan.Main
java -m jdk.jdeps/com.sun.tools.jdeps.Main
java -m jdk.jdeps/com.sun.tools.jdeps.Profile
java -m jdk.jdi/com.sun.tools.example.debug.expr.ExpressionParser
java -m jdk.jdi/com.sun.tools.example.debug.tty.TTY
java -m jdk.jfr/jdk.jfr.internal.tool.Main
java -m jdk.jfr/jdk.jfr.snippets.Snippets
java -m jdk.jfr/jdk.jfr.snippets.Snippets$ConfigurationOverview
java -m jdk.jfr/jdk.jfr.snippets.Snippets$Example
java -m jdk.jfr/jdk.jfr.snippets.consumer.Snippets$EventStreamMetadata
java -m jdk.jfr/jdk.jfr.snippets.consumer.Snippets$PackageOverview
java -m jdk.jlink/jdk.tools.jimage.Main
java -m jdk.jlink/jdk.tools.jlink.internal.Main
java -m jdk.jlink/jdk.tools.jmod.Main
java -m jdk.jpackage/jdk.jpackage.main.Main
java -m jdk.jshell/jdk.internal.jshell.tool.JShellToolProvider
java -m jdk.jshell/jdk.jshell.execution.RemoteExecutionControl
java -m jdk.jstatd/sun.tools.jstatd.Jstatd
java -m jdk.security.auth/com.sun.security.auth.module.Crypt
java -m jdk.zipfs/jdk.nio.zipfs.ZipInfo

Executable main classes in JDK 8

java -DshowCommand=true --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED MainMethodFinder.java ~/.sdkman/candidates/java/8.0.282.hs-adpt

Output JDK 8

/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/jconsole.jar sun.tools.jconsole.JConsole
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/jfr.jar jdk.jfr.internal.tool.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/ext/nashorn.jar jdk.nashorn.tools.Shell
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.activation.ORBD
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.activation.RepositoryImpl
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.activation.ServerMain
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.activation.ServerTool
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.naming.cosnaming.TransientNameServer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.naming.pcosnaming.NameServer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.util.JDKBridge
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.util.ORBProperties
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.impl.util.Version
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.internal.CosNaming.BootstrapServer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.corba.se.spi.orbutil.fsm.FSMTest
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.java.util.jar.pack.Driver
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xalan.internal.xslt.EnvironmentCheck
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xalan.internal.xsltc.ProcessorVersion
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xalan.internal.xsltc.cmdline.Compile
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xalan.internal.xsltc.cmdline.Transform
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xerces.internal.impl.Constants
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xerces.internal.impl.Version
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xerces.internal.impl.xpath.XPath
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xerces.internal.impl.xpath.regex.REUtil
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.org.apache.xml.internal.security.keys.storage.implementations.CertsInFilesystemDirectoryResolver
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.security.auth.module.Crypt
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.FI_DOM_Or_XML_DOM_SAX_SAXEvent
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.FI_SAX_Or_XML_SAX_DOM_SAX_SAXEvent
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.FI_SAX_Or_XML_SAX_SAXEvent
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.FI_SAX_XML
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.FI_StAX_SAX_Or_XML_SAX_SAXEvent
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.PrintTable
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.XML_DOM_FI
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.XML_DOM_SAX_FI
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.XML_SAX_FI
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar com.sun.xml.internal.fastinfoset.tools.XML_SAX_StAX_FI
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar java.util.prefs.Base64
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar jdk.internal.org.objectweb.asm.util.ASMifier
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar jdk.internal.org.objectweb.asm.util.CheckClassAdapter
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar jdk.internal.org.objectweb.asm.util.Textifier
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.applet.AppletViewer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.applet.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.java2d.loops.GraphicsPrimitiveMgr
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.launcher.LauncherHelper$FXHelper
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.net.NetworkServer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.rmi.registry.RegistryImpl
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.rmi.server.Activation
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.rmi.server.ActivationGroupInit
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.rmi.transport.proxy.CGIHandler
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.security.provider.PolicyParser
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.security.tools.keytool.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.security.tools.policytool.PolicyTool
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/rt.jar sun.tools.jar.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar com.sun.java.swing.ui.TabsDlg
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar com.sun.java.swing.ui.WizardDlg
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.CLHSDB
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.DebugServer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.HSDB
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.HelloWorld
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.ObjectHistogram
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.StackTrace
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.bsd.BsdAddress
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.dummy.DummyAddress
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.linux.LinuxAddress
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.posix.elf.ELFFileParser
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.proc.ProcAddress
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.remote.RemoteAddress
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.win32.coff.DumpExports
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.win32.coff.TestDebugInfo
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.win32.coff.TestParser
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.debugger.windbg.WindbgAddress
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.jdi.SADebugServer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.ClassLoaderStats
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.FinalizerInfo
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.FlagDumper
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.HeapDumper
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.HeapSummary
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.JInfo
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.JMap
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.JSnap
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.JStack
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.ObjectHistogram
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.PMap
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.PStack
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.StackTrace
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.SysPropsDumper
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.jcore.ClassDump
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.soql.JSDB
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.tools.soql.SOQL
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.ui.AnnotatedMemoryPanel
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.ui.CommandProcessorPanel
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.ui.DebuggerConsolePanel
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.ui.HighPrecisionJScrollBar
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.ui.ObjectHistogramPanel
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.utilities.PlatformInfo
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/sa-jdi.jar sun.jvm.hotspot.utilities.RBTree
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.corba.se.idl.Compile
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.corba.se.idl.toJavaPortable.Compile
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.doclint.DocLint
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.example.debug.expr.ExpressionParser
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.example.debug.tty.TTY
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.extcheck.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.hat.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.jxc.SchemaGenerator
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.jxc.SchemaGeneratorFacade
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.ws.WsGen
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.ws.WsImport
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.xjc.Driver
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.xjc.XJCFacade
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.xjc.reader.xmlschema.parser.SchemaConstraintChecker
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.internal.xjc.util.MimeTypeRange
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.javac.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.javac.sym.CreateSymbols
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.javac.sym.Profiles
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.javac.util.Bits
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.javadoc.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.javah.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.javap.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.jdeps.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.jdeps.Profile
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.tools.script.shell.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.xml.internal.rngom.digested.DXMLPrinter
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.xml.internal.rngom.digested.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar com.sun.xml.internal.rngom.xml.util.EncodingMap
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.applet.AppletViewer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.applet.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.rmi.rmic.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.rmi.rmic.iiop.StaticStringsHash
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.rmi.rmic.newrmic.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.security.tools.jarsigner.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jar.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.javac.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jcmd.JCmd
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jinfo.JInfo
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jmap.JMap
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jps.Jps
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jstack.JStack
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jstat.Jstat
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.jstatd.Jstatd
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.native2ascii.Main
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/lib/tools.jar sun.tools.serialver.SerialVer
/home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/bin/java -cp /home/tom/.sdkman/candidates/java/8.0.282.hs-adpt/jre/lib/ext/zipfs.jar com.sun.nio.zipfs.ZipInfo

import jdk.internal.org.objectweb.asm.*;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Consumer;
/**
* Run:
* <pre>java --show-version -DshowCommand=true --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED MainMethodFinder.java</pre>
* <p>
* Run with different Java Home:
* <pre>java -DshowCommand=true --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED MainMethodFinder.java ~/.sdkman/candidates/java/8.0.282.hs-adpt</pre>
* <p>
* Compile with GraalVM Native Image:
* <pre>native-image -cp target/classes wb.java21.MainMethodFinder MainMethodFinder</pre>
* <p>
* Run GraalVM Native Image
* <pre>./MainMethodFinder -DshowCommand=true ~/.sdkman/candidates/java/8.0.282.hs-adpt</pre>
* <pre>./MainMethodFinder -DshowCommand=true ~/.sdkman/candidates/java/11.0.10.hs-adpt</pre>
*/
public class MainMethodFinder {
private static final boolean VERBOSE = Boolean.getBoolean("verbose");
private static final boolean IS_NATIVE_IMAGE = System.getProperty("org.graalvm.nativeimage.imagecode") != null;
private static final boolean SHOW_COMMAND = Boolean.getBoolean("showCommand");
public static void main(String[] args) throws IOException {
long time = System.nanoTime();
try {
boolean customJdkPathProvided = args.length > 0;
if (!customJdkPathProvided && IS_NATIVE_IMAGE) {
System.err.println("MainMethodFinder: Missing path operand.");
System.err.println("Usage: MainMethodFinder /path/to/jdk");
System.exit(-1);
return;
}
var jdkHomePath = customJdkPathProvided ? Path.of(args[0]) : detectCurrentJdkPath();
if (VERBOSE) {
System.out.printf("Scanning Java Installation: %s%n", jdkHomePath);
}
MainMethodReportingVisitor visitor = new MainMethodReportingVisitor();
Files.walkFileTree(jdkHomePath, visitor);
Consumer<MainMethod> printMainMethodInfo = mainMethod -> {
String libraryFileName = mainMethod.library.getName();
if (libraryFileName.endsWith(".jar")) {
libraryFileName = jdkHomePath.relativize(mainMethod.library.toPath()).toString();
}
String mainClassName = mainMethod.className;
String libraryName = libraryFileName.replaceAll("\\.jmod", "");
if (SHOW_COMMAND) {
String launchCommand = generateLaunchCommand(!customJdkPathProvided, jdkHomePath, libraryFileName, mainClassName, libraryName);
System.out.printf("%s%n", launchCommand);
} else {
System.out.printf("%s %s%n", libraryName, mainClassName);
}
};
var mainMethods = visitor.waitForCompletionAndReturnMainMethods();
mainMethods.forEach(printMainMethodInfo);
} finally {
time = System.nanoTime() - time;
if (VERBOSE) {
System.out.printf("time = %dms%n", TimeUnit.NANOSECONDS.toMillis(time));
// System.out.printf("ForkJoin Pool Stats: %s%n", ForkJoinPool.commonPool());
}
}
}
private static String generateLaunchCommand(boolean useCurrentJdk, Path jdkHomePath, String libraryFileName, String mainClassName, String libraryName) {
var launchCommand = (useCurrentJdk ? "" : jdkHomePath.toFile().getAbsolutePath() + "/bin/") + "java";
if (libraryFileName.endsWith(".jmod")) {
launchCommand += (useCurrentJdk ? "" : " --module-path " + jdkHomePath.toFile().getAbsolutePath() + "/jmods");
launchCommand += " -m " + libraryName + "/" + mainClassName;
} else if (libraryFileName.endsWith(".jar")) {
launchCommand += " -cp " + jdkHomePath.toFile().getAbsolutePath() + "/" + libraryFileName;
launchCommand += " " + mainClassName;
} else {
launchCommand = String.format("Could not generate launch command for: %s %s", libraryFileName, mainClassName);
}
return launchCommand;
}
private static Path detectCurrentJdkPath() {
return Paths.get(ProcessHandle.current().info().command().orElseThrow()).resolve("../..").normalize();
}
}
class MainMethodReportingVisitor extends SimpleFileVisitor<Path> {
private final CopyOnWriteArrayList<MainMethod> mainMethods = new CopyOnWriteArrayList<>();
private final Queue<RecursiveAction> outstanding = new ConcurrentLinkedQueue<>();
@Override
public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) {
var maybeJdkLibrary = filePath.toFile();
if (isJdkLibrary(maybeJdkLibrary.getName())) {
var action = new RecursiveAction() {
protected void compute() {
scanLibraryForMainClasses(maybeJdkLibrary);
}
};
action.fork();
outstanding.add(action);
}
return FileVisitResult.CONTINUE;
}
public List<MainMethod> waitForCompletionAndReturnMainMethods() {
for (RecursiveAction action; (action = outstanding.poll()) != null; ) {
action.join();
}
List<MainMethod> result = new ArrayList<>(this.mainMethods);
this.mainMethods.clear();
var cmp = Comparator.comparing((MainMethod left) -> left.library.getName()).thenComparing((MainMethod left) -> left.className);
result.sort(cmp);
return result;
}
private boolean isJdkLibrary(String maybeJdkLibraryName) {
return maybeJdkLibraryName.endsWith(".jar") || maybeJdkLibraryName.endsWith(".jmod");
}
private void scanLibraryForMainClasses(File library) {
// Using FileSystems.newFileSystem(library.toPath(), (ClassLoader)null) for Java 11 compatibility
try (var fileSystem = FileSystems.newFileSystem(library.toPath(), (ClassLoader) null)) {
var root = fileSystem.getRootDirectories().iterator().next();
var visitor = new MainMethodVisitor(library, mainMethods::add, fileSystem);
try (var files = Files.walk(root).parallel().filter(this::isClassFile)) {
files.forEach(visitor::scanClassForMainMethod);
}
} catch (Exception e) {
System.err.println("Could not scan library: " + library.getAbsolutePath());
e.printStackTrace();
}
}
private boolean isClassFile(Path nestedFilePath) {
return nestedFilePath.toString().endsWith(".class");
}
}
// we don't use record here to support JDKs < 16
class MainMethod {
final File library;
final String className;
public MainMethod(File library, String className) {
this.library = library;
this.className = className;
}
}
class MainMethodVisitor extends ClassVisitor {
// Adapted from Opcodes.ASM* to be usable across jdk versions.
private static final int ASM6 = 6 << 16;
private static final int ASM7 = 7 << 16;
private static final int ASM8 = 8 << 16;
private static final int ASM9 = 9 << 16;
private static final String JAVA_VERSION_STRING = System.getProperty("java.version");
private static final int ASM_API_VERSION =
// not using Opcodes.* constants to support running on Java11-21
JAVA_VERSION_STRING.startsWith("11.") //
? ASM6 //
: JAVA_VERSION_STRING.startsWith("15.") //
? ASM7 //
: JAVA_VERSION_STRING.startsWith("20.") //
? ASM8 //
: ASM9;
private final File library;
private final FileSystem fileSystem;
private final Consumer<MainMethod> mainMethodConsumer;
private final ThreadLocal<String> currentInternalClassName;
public MainMethodVisitor(File library, Consumer<MainMethod> mainMethodConsumer, FileSystem fileSystem) {
super(ASM_API_VERSION);
this.library = library;
this.fileSystem = fileSystem;
this.mainMethodConsumer = mainMethodConsumer;
this.currentInternalClassName = new ThreadLocal<>();
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
currentInternalClassName.set(name);
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public void visitEnd() {
super.visitEnd();
currentInternalClassName.remove();
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
if (isRunnableMainMethod(access, name, descriptor)) {
mainMethodConsumer.accept(new MainMethod(library, currentInternalClassName.get().replace('/', '.')));
}
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
private boolean isRunnableMainMethod(int access, String name, String descriptor) {
return "main".equals(name) && (access & Opcodes.ACC_STATIC) != 0 && "([Ljava/lang/String;)V".equals(descriptor);
}
void scanClassForMainMethod(Path pathToLibraryClass) {
tryGetClassBytes(pathToLibraryClass, fileSystem).ifPresent(this::visitClassBytes);
}
private void visitClassBytes(byte[] classBytes) {
new ClassReader(classBytes).accept(this, 0);
}
private Optional<byte[]> tryGetClassBytes(Path nestedFilePath, FileSystem fileSystem) {
// use filesystem to access .jar and .jmod file contents
try (var is = fileSystem.provider().newInputStream(nestedFilePath)) {
return Optional.of(is.readAllBytes());
} catch (IOException e) {
e.printStackTrace();
}
return Optional.empty();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment