{"id":107,"date":"2010-08-23T21:42:48","date_gmt":"2010-08-23T20:42:48","guid":{"rendered":"http:\/\/benjiweber.co.uk\/blog\/?p=107"},"modified":"2010-08-23T21:42:48","modified_gmt":"2010-08-23T20:42:48","slug":"java-abuse-public-static-void-main-was-not-invented-here","status":"publish","type":"post","link":"https:\/\/benjiweber.co.uk\/blog\/2010\/08\/23\/java-abuse-public-static-void-main-was-not-invented-here\/","title":{"rendered":"Java Abuse: public static void main was not invented here."},"content":{"rendered":"<p class=\"lead\">Normally a command-line Java application will have an entry method that looks something like:<\/p>\n<pre lang=\"java\">\r\npublic static void main(String... args) {\r\n    \/* Code that launches the application\/deals with command line params here *\/\r\n}\r\n<\/pre>\n<p>This is far too easy, there must be a way to NIH it \u00ac_\u00ac. There are a few annoyances with the public static void main method.<\/p>\n<ul>\n<li>Args are passed in as an Array, rather than something like a List&lt;String&gt;<\/li>\n<li>We can&#8217;t choose to call the main method something other than main.<\/li>\n<li>It&#8217;s a bit obscure how the startup process works.<\/li>\n<\/ul>\n<p>There is a common way to execute code on app startup without using a static void main method. You can use a static initialization block:<\/p>\n<pre lang=\"java\">\r\nstatic {\r\n    \/* Code here run on class load. *\/\r\n}\r\n<\/pre>\n<p>So we could launch our application from within a static initialization block. However this presents a number of problems:<\/p>\n<ol>\n<li>We get a nasty error when the application finishes (Exception in thread &#8220;main&#8221; java.lang.NoSuchMethodError: main)<\/li>\n<li>We have no access to the command line arguments<\/li>\n<li>We can&#8217;t have multiple &#8220;Main&#8221; classes with this method (Both static initialization blocks will be run, if both classes are loaded)<\/li>\n<li>It doesn&#8217;t really provide any benefits over static void main.<\/li>\n<\/ol>\n<p>These problems can, however, all be overcome. <\/p>\n<h3>Suppressing NoSuchMethodError<\/h3>\n<p>We can just call System.err.close(); at the end of our initialization method.<\/p>\n<h3>Access to the command line arguments<\/h3>\n<p>This one is probably the most difficult. I&#8217;ve not found any &#8220;good&#8221; way to do this, but there is a hack that works at present on Sun&#8217;s Java, though it may stop working at any point. <\/p>\n<pre lang=\"java\">\r\nsun.misc.VMSupport.getAgentProperties().get(\"sun.java.command\")\r\n<\/pre>\n<p>This will give the command line string used to start the application. There are alternatives involving attaching to the currently running VM with the Agent API or shelling out to external processes and using platform-specific commands to work out the command used to start the application. If anyone knows a proper way to access the command line arguments using the public API then please let me know.<\/p>\n<h3>Multiple Main Classes<\/h3>\n<p>We need to get our initialization system to ignore invocations from classes other than the one used to start our application. This can be done by checking the length of the StackTrace. e.g.<\/p>\n<pre lang=\"java\">\r\nnew Throwable().fillInStackTrace().getStackTrace().length == 2;\r\n<\/pre>\n<h3>Reflection Examples<\/h3>\n<p>With these 3 issues solved it&#8217;s possible to do things like:<\/p>\n<pre lang=\"java\">\r\npackage MainlessDemo;\r\n\r\nimport java.util.List;\r\nimport static uk.co.benjiweber.realjava.mainless.Bootstrap.init;\r\n\r\npublic class ReflectionMainless {\r\n\tstatic { init(); }\r\n\tpublic void main(final List<String> args) {\r\n\t\tSystem.out.println(\"Hello World\");\r\n\t\tSystem.err.println(\"From std err\");\r\n\t\tfor (String arg : args) {\r\n\t\t\tSystem.out.println(arg);\t\r\n\t\t}\r\n\t}\r\n}\r\n\/* Output:\r\n$ javac -cp .:.\/RealJava.jar .\/MainlessDemo\/*.java && java -cp .:.\/RealJava.jar MainlessDemo.ReflectionMainless Foo Bar Baz\r\nHello World\r\nFrom std err\r\nFoo\r\nBar\r\nBaz\r\n*\/\r\n<\/pre>\n<p>Here a statically imported &#8220;init&#8221; method instantiates our main class, invokes our non-static main method, and passes it the command line arguments. The class to instantiate can be determined by walking back up the stack trace again.<\/p>\n<p>We can also inject constructor arguments if we wish:<\/p>\n<pre lang=\"java\">\r\npackage MainlessDemo;\r\n\r\nimport java.util.List;\r\nimport static uk.co.benjiweber.realjava.mainless.Bootstrap.init;\r\n\r\npublic class ReflectionMainlessWithArgs {\r\n\t\r\n\t\/\/ This time we pass in the constructor argument\r\n\tstatic { init(\"Hello World\"); }\r\n\t\r\n\tprivate final String message;\r\n\t\r\n\t\/\/ Even though we load another class that is Launchable it doesn't get launched.\r\n\tstatic final ReflectionMainless test = new ReflectionMainless(); \r\n\t\r\n\tpublic ReflectionMainlessWithArgs(final String message) {\r\n\t\tthis.message = message;\r\n\t}\r\n\t\r\n\tpublic void main(final List<String> args) {\r\n\t\tSystem.out.println(message + \" (Passed in through constructor)\");\r\n\t\tfor (String arg : args) {\r\n\t\t\tSystem.out.println(arg);\t\r\n\t\t}\r\n\t}\r\n}\r\n\/* Output:\r\n$ javac -cp .:.\/RealJava.jar .\/MainlessDemo\/*.java && java -cp .:.\/RealJava.jar MainlessDemo.ReflectionMainlessWithArgs Foo Bar Baz\r\nHello World (Passed in through constructor)\r\nFoo\r\nBar\r\nBaz\r\n\r\n*\/\r\n<\/pre>\n<h3>Interface Examples<\/h3>\n<p>Unfortunately, apart from substituting an argument Array for a List, we &#8216;ve not really improved anything. However, now that we&#8217;re in control of the initialization process we can do more interesting things, like use an interface:<\/p>\n<pre lang=\"java\">\r\npublic interface Launchable {\r\n\tpublic void main(List<String> args);\r\n}\r\n<\/pre>\n<pre lang=\"java\">\r\npackage MainlessDemo;\r\n\r\nimport java.util.List;\r\nimport uk.co.benjiweber.realjava.mainless.Launchable;\r\nimport static uk.co.benjiweber.realjava.mainless.Bootstrap.init;\r\n\r\npublic class SaferMainless implements Launchable {\r\n\tstatic { init(new SaferMainless()); }\r\n\t\r\n\tpublic void main(final List<String> args) {\r\n\t\tSystem.out.println(\"Hello from a Launchable\");\r\n\t\tfor (String arg : args) {\r\n\t\t\tSystem.out.println(arg);\t\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\/*\r\nOutput:\r\n$ javac -cp .:.\/RealJava.jar .\/MainlessDemo\/*.java && java -cp .:.\/RealJava.jar MainlessDemo.SaferMainless Foo Bar Baz\r\nHello from a Launchable\r\nFoo\r\nBar\r\nBaz\r\n*\/\r\n<\/pre>\n<p>Now it&#8217;s clearer how the initialization process works, you can use your IDE to follow execution through from the init block to the main method. This also gives us the freedom to call our main method something different, and inject dependencies before reaching the main method.<\/p>\n<pre lang=\"java\">\r\npackage MainlessDemo;\r\n\r\nimport java.util.List;\r\nimport uk.co.benjiweber.realjava.mainless.Launchable;\r\nimport static uk.co.benjiweber.realjava.mainless.Bootstrap.init;\r\n\r\npublic class SaferAnonymousMainless {\r\n\t\r\n\tstatic { init(new Launchable() {\r\n\t\tpublic void main(final List<String> args) {\r\n\t\t\tSaferAnonymousMainless mainless = new SaferAnonymousMainless();\r\n\t\t\tmainless.setMessage(\"I was injected manually\");\r\n\t\t\tmainless.someMethodNotCalledMain(args);\r\n\t\t}\r\n\t}); }\r\n\t\r\n\tprivate String message;\r\n\t\r\n\tpublic void setMessage(final String message) {\r\n\t\tthis.message = message;\r\n\t}\r\n\t\r\n\tpublic void someMethodNotCalledMain(final List<String> args) {\r\n\t\tSystem.out.println(message);\r\n\t\tfor (String arg : args) {\r\n\t\t\tSystem.out.println(arg);\t\r\n\t\t}\r\n\t}\r\n}\r\n\/* \r\nOutput:\r\n$ javac -cp .:.\/RealJava.jar .\/MainlessDemo\/*.java && java -cp .:.\/RealJava.jar MainlessDemo.SaferAnonymousMainless Foo Bar Baz\r\nI was injected manually\r\nFoo\r\nBar\r\nBaz\r\n\r\n*\/\r\n<\/pre>\n<p><a href=\"http:\/\/github.com\/benjiman\/realjava\/blob\/master\/src\/main\/java\/uk\/co\/benjiweber\/realjava\/mainless\/Bootstrap.java\">Source for the BootStrap.init method is here<\/a><\/p>\n<p>Thanks to <a href=\"http:\/\/blog.prelode.com\/\">Faux<\/a> for some of the ideas.<\/p>\n<p>Yes I know this isn&#8217;t remotely a good idea, no need to tell me :) <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Normally a command-line Java application will have an entry method that looks something like: public static void main(String&#8230; args) { \/* Code that launches the application\/deals with command line params here *\/ } This is far too easy, there must be a way to NIH it \u00ac_\u00ac. There are a few annoyances with the public&#8230;  <a href=\"https:\/\/benjiweber.co.uk\/blog\/2010\/08\/23\/java-abuse-public-static-void-main-was-not-invented-here\/\" class=\"more-link\" title=\"Read Java Abuse: public static void main was not invented here.\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v14.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/benjiweber.co.uk\/blog\/2010\/08\/23\/java-abuse-public-static-void-main-was-not-invented-here\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Java Abuse: public static void main was not invented here. - Benji&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"Normally a command-line Java application will have an entry method that looks something like: public static void main(String... args) { \/* Code that launches the application\/deals with command line params here *\/ } This is far too easy, there must be a way to NIH it \u00ac_\u00ac. There are a few annoyances with the public... Read more &raquo;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/benjiweber.co.uk\/blog\/2010\/08\/23\/java-abuse-public-static-void-main-was-not-invented-here\/\" \/>\n<meta property=\"og:site_name\" content=\"Benji&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2010-08-23T20:42:48+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#website\",\"url\":\"https:\/\/benjiweber.co.uk\/blog\/\",\"name\":\"Benji&#039;s Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/benjiweber.co.uk\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/2010\/08\/23\/java-abuse-public-static-void-main-was-not-invented-here\/#webpage\",\"url\":\"https:\/\/benjiweber.co.uk\/blog\/2010\/08\/23\/java-abuse-public-static-void-main-was-not-invented-here\/\",\"name\":\"Java Abuse: public static void main was not invented here. - Benji&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#website\"},\"datePublished\":\"2010-08-23T20:42:48+00:00\",\"dateModified\":\"2010-08-23T20:42:48+00:00\",\"author\":{\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#\/schema\/person\/45ecb36b51f4ce99e6929d2d31ca5c09\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/benjiweber.co.uk\/blog\/2010\/08\/23\/java-abuse-public-static-void-main-was-not-invented-here\/\"]}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#\/schema\/person\/45ecb36b51f4ce99e6929d2d31ca5c09\",\"name\":\"benji\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/05fb47b31a0b329e1b790074a9b624ef?s=96&d=mm&r=g\",\"caption\":\"benji\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts\/107"}],"collection":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=107"}],"version-history":[{"count":12,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts\/107\/revisions"}],"predecessor-version":[{"id":119,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts\/107\/revisions\/119"}],"wp:attachment":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=107"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=107"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=107"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}