diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/RunJar.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/RunJar.java index 50126002b7be7..ea1cc40a96a68 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/RunJar.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/RunJar.java @@ -24,6 +24,7 @@ import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -315,6 +316,11 @@ public void run() { Thread.currentThread().setContextClassLoader(loader); Class mainClass = Class.forName(mainClassName, true, loader); Method main = mainClass.getMethod("main", String[].class); + + if (!Modifier.isStatic(main.getModifiers())) { + throw new IOException("Method main must be static: " + mainClassName); + } + List newArgsSubList = Arrays.asList(args) .subList(firstArg, args.length); String[] newArgs = newArgsSubList diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/NonStaticMain.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/NonStaticMain.java new file mode 100644 index 0000000000000..d22915b3df494 --- /dev/null +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/NonStaticMain.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.util; + +/** + * NonStaticMain is used to test classes which provide a main which + * isn't static. + */ +public class NonStaticMain { + public void main(String[] args) { + } +} diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestRunJar.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestRunJar.java index 1f7c71222fbfe..c7e3fde3d7913 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestRunJar.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestRunJar.java @@ -57,7 +57,7 @@ public class TestRunJar { private static final int BUFF_SIZE = 2048; private File TEST_ROOT_DIR; - private static final String TEST_JAR_NAME="test-runjar.jar"; + private static final String TEST_JAR_NAME = "test-runjar.jar"; private static final String TEST_JAR_2_NAME = "test-runjar2.jar"; private static final long MOCKED_NOW = 1_460_389_972_000L; private static final long MOCKED_NOW_PLUS_TWO_SEC = MOCKED_NOW + 2_000; @@ -297,4 +297,35 @@ public void testUnJar2() throws IOException { "would create file outside of", e); } } -} \ No newline at end of file + + /** + * Tests that RunJar errors appropriately for classes with non-static main + * methods. + */ + @Test + public void testRunNonStaticMain() throws Throwable { + RunJar runJar = spy(new RunJar()); + // enable the client classloader + when(runJar.useClientClassLoader()).thenReturn(true); + // set the system classes and blacklist the test main class so it + // can be loaded by the application classloader + String mainCls = NonStaticMain.class.getName(); + String systemClasses = "-" + mainCls + "," + + ApplicationClassLoader.SYSTEM_CLASSES_DEFAULT; + when(runJar.getSystemClasses()).thenReturn(systemClasses); + + // create the test jar + File testJar = JarFinder.makeClassLoaderTestJar(this.getClass(), + TEST_ROOT_DIR, TEST_JAR_2_NAME, BUFF_SIZE, mainCls); + // form the args + String[] args = new String[] {testJar.getAbsolutePath(), mainCls}; + + // run RunJar + try { + runJar.run(args); + fail("run should throw IOException."); + } catch (IOException e) { + GenericTestUtils.assertExceptionContains("Method main must be static", e); + } + } +}