diff --git a/Java/commons-lang-MethodUtilsTest_711/Dockerfile b/Java/commons-lang-MethodUtilsTest_711/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MethodUtilsTest_711/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MethodUtilsTest_711/buggy.java b/Java/commons-lang-MethodUtilsTest_711/buggy.java new file mode 100644 index 000000000..943c7a905 --- /dev/null +++ b/Java/commons-lang-MethodUtilsTest_711/buggy.java @@ -0,0 +1,788 @@ +/* + * 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.commons.lang3.reflect; + +import static org.hamcrest.Matchers.hasItemInArray; +import static org.hamcrest.Matchers.hasItems; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.commons.lang3.mutable.Mutable; +import org.apache.commons.lang3.mutable.MutableObject; +import org.apache.commons.lang3.reflect.testbed.Annotated; +import org.apache.commons.lang3.reflect.testbed.GenericConsumer; +import org.apache.commons.lang3.reflect.testbed.GenericParent; +import org.apache.commons.lang3.reflect.testbed.StringParameterizedChild; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests MethodUtils + */ +public class MethodUtilsTest { + + private static interface PrivateInterface {} + + static class TestBeanWithInterfaces implements PrivateInterface { + public String foo() { + return "foo()"; + } + } + + public static class TestBean { + + public static String bar() { + return "bar()"; + } + + public static String bar(final int i) { + return "bar(int)"; + } + + public static String bar(final Integer i) { + return "bar(Integer)"; + } + + public static String bar(final double d) { + return "bar(double)"; + } + + public static String bar(final String s) { + return "bar(String)"; + } + + public static String bar(final Object o) { + return "bar(Object)"; + } + + public static String bar(final String... s) { + return "bar(String...)"; + } + + public static String bar(final Integer i, final String... s) { + return "bar(int, String...)"; + } + + public static void oneParameterStatic(final String s) { + // empty + } + + @SuppressWarnings("unused") + private void privateStuff() { + } + + @SuppressWarnings("unused") + private String privateStringStuff() { + return "privateStringStuff()"; + } + + @SuppressWarnings("unused") + private String privateStringStuff(final int i) { + return "privateStringStuff(int)"; + } + + @SuppressWarnings("unused") + private String privateStringStuff(final Integer i) { + return "privateStringStuff(Integer)"; + } + + @SuppressWarnings("unused") + private String privateStringStuff(final double d) { + return "privateStringStuff(double)"; + } + + @SuppressWarnings("unused") + private String privateStringStuff(final String s) { + return "privateStringStuff(String)"; + } + + @SuppressWarnings("unused") + private String privateStringStuff(final Object s) { + return "privateStringStuff(Object)"; + } + + + public String foo() { + return "foo()"; + } + + public String foo(final int i) { + return "foo(int)"; + } + + public String foo(final Integer i) { + return "foo(Integer)"; + } + + public String foo(final double d) { + return "foo(double)"; + } + + public String foo(final String s) { + return "foo(String)"; + } + + public String foo(final Object o) { + return "foo(Object)"; + } + + public String foo(final String... s) { + return "foo(String...)"; + } + + public String foo(final Integer i, final String... s) { + return "foo(int, String...)"; + } + + public void oneParameter(final String s) { + // empty + } + + public String foo(final Object... s) { + return "foo(Object...)"; + } + + public int[] unboxing(int... values) { + return values; + } + + // This method is overloaded for the wrapper class for every primitive type, plus the common supertypes + // Number and Object. This is an acid test since it easily leads to ambiguous methods. + public static String varOverload(Byte... args) { return "Byte..."; } + public static String varOverload(Character... args) { return "Character..."; } + public static String varOverload(Short... args) { return "Short..."; } + public static String varOverload(Boolean... args) { return "Boolean..."; } + public static String varOverload(Float... args) { return "Float..."; } + public static String varOverload(Double... args) { return "Double..."; } + public static String varOverload(Integer... args) { return "Integer..."; } + public static String varOverload(Long... args) { return "Long..."; } + public static String varOverload(Number... args) { return "Number..."; } + public static String varOverload(Object... args) { return "Object..."; } + public static String varOverload(String... args) { return "String..."; } + + // This method is overloaded for the wrapper class for every numeric primitive type, plus the common + // supertype Number + public static String numOverload(Byte... args) { return "Byte..."; } + public static String numOverload(Short... args) { return "Short..."; } + public static String numOverload(Float... args) { return "Float..."; } + public static String numOverload(Double... args) { return "Double..."; } + public static String numOverload(Integer... args) { return "Integer..."; } + public static String numOverload(Long... args) { return "Long..."; } + public static String numOverload(Number... args) { return "Number..."; } + + // These varOverloadEcho and varOverloadEchoStatic methods are designed to verify that + // not only is the correct overloaded variant invoked, but that the varags arguments + // are also delivered correctly to the method. + public ImmutablePair varOverloadEcho(String... args) { + return new ImmutablePair("String...", args); + } + public ImmutablePair varOverloadEcho(Number... args) { + return new ImmutablePair("Number...", args); + } + + public static ImmutablePair varOverloadEchoStatic(String... args) { + return new ImmutablePair("String...", args); + } + public static ImmutablePair varOverloadEchoStatic(Number... args) { + return new ImmutablePair("Number...", args); + } + + static void verify(ImmutablePair a, ImmutablePair b) { + assertEquals(a.getLeft(), b.getLeft()); + assertArrayEquals(a.getRight(), b.getRight()); + } + + static void verify(ImmutablePair a, Object _b) { + @SuppressWarnings("unchecked") + final ImmutablePair b = (ImmutablePair) _b; + verify(a, b); + } + + } + + private static class TestMutable implements Mutable { + @Override + public Object getValue() { + return null; + } + + @Override + public void setValue(final Object value) { + } + } + + private TestBean testBean; + private final Map, Class[]> classCache = new HashMap, Class[]>(); + + @Before + public void setUp() throws Exception { + testBean = new TestBean(); + classCache.clear(); + } + + @Test + public void testConstructor() throws Exception { + assertNotNull(MethodUtils.class.newInstance()); + } + + @Test + public void verifyJavaVarargsOverloadingResolution() throws Exception { + // This code is not a test of MethodUtils. + // Rather it makes explicit the behavior of the Java specification for + // various cases of overload resolution. + assertEquals("Byte...", TestBean.varOverload((byte) 1, (byte) 2)); + assertEquals("Short...", TestBean.varOverload((short) 1, (short) 2)); + assertEquals("Integer...", TestBean.varOverload(1, 2)); + assertEquals("Long...", TestBean.varOverload(1L, 2L)); + assertEquals("Float...", TestBean.varOverload(1f, 2f)); + assertEquals("Double...", TestBean.varOverload(1d, 2d)); + assertEquals("Character...", TestBean.varOverload('a', 'b')); + assertEquals("String...", TestBean.varOverload("a", "b")); + assertEquals("Boolean...", TestBean.varOverload(true, false)); + + assertEquals("Object...", TestBean.varOverload(1, "s")); + assertEquals("Object...", TestBean.varOverload(1, true)); + assertEquals("Object...", TestBean.varOverload(1.1, true)); + assertEquals("Object...", TestBean.varOverload('c', true)); + assertEquals("Number...", TestBean.varOverload(1, 1.1)); + assertEquals("Number...", TestBean.varOverload(1, 1L)); + assertEquals("Number...", TestBean.varOverload(1d, 1f)); + assertEquals("Number...", TestBean.varOverload((short) 1, (byte) 1)); + assertEquals("Object...", TestBean.varOverload(1, 'c')); + assertEquals("Object...", TestBean.varOverload('c', "s")); + } + + @Test + public void testInvokeJavaVarargsOverloadingResolution() throws Exception { + assertEquals("Byte...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", (byte) 1, (byte) 2)); + assertEquals("Short...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", (short) 1, (short) 2)); + assertEquals("Integer...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1, 2)); + assertEquals("Long...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1L, 2L)); + assertEquals("Float...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1f, 2f)); + assertEquals("Double...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1d, 2d)); + assertEquals("Character...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 'a', 'b')); + assertEquals("String...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", "a", "b")); + assertEquals("Boolean...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", true, false)); + + assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1, "s")); + assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1, true)); + assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1.1, true)); + assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 'c', true)); + assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1, 1.1)); + assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1, 1L)); + assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1d, 1f)); + assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", (short) 1, (byte) 1)); + assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 1, 'c')); + assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, + "varOverload", 'c', "s")); + + assertEquals("Object...", MethodUtils.invokeStaticMethod(TestBean.class, "varOverload", + (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); + assertEquals("Number...", MethodUtils.invokeStaticMethod(TestBean.class, "numOverload", + (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); + } + + @Test + public void testInvokeMethod() throws Exception { + assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", + (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); + assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo")); + assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", + (Object[]) null)); + assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo", + (Object[]) null, (Class[]) null)); + assertEquals("foo(String)", MethodUtils.invokeMethod(testBean, "foo", + "")); + assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", + new Object())); + assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo", + Boolean.TRUE)); + assertEquals("foo(Integer)", MethodUtils.invokeMethod(testBean, "foo", + NumberUtils.INTEGER_ONE)); + assertEquals("foo(int)", MethodUtils.invokeMethod(testBean, "foo", + NumberUtils.BYTE_ONE)); + assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo", + NumberUtils.LONG_ONE)); + assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo", + NumberUtils.DOUBLE_ONE)); + assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo", + "a", "b", "c")); + assertEquals("foo(String...)", MethodUtils.invokeMethod(testBean, "foo", + "a", "b", "c")); + assertEquals("foo(int, String...)", MethodUtils.invokeMethod(testBean, "foo", + 5, "a", "b", "c")); + + TestBean.verify(new ImmutablePair("String...", new String[]{"x", "y"}), + MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y")); + TestBean.verify(new ImmutablePair("Number...", new Number[]{17, 23, 42}), + MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42)); + TestBean.verify(new ImmutablePair("String...", new String[]{"x", "y"}), + MethodUtils.invokeMethod(testBean, "varOverloadEcho", "x", "y")); + TestBean.verify(new ImmutablePair("Number...", new Number[]{17, 23, 42}), + MethodUtils.invokeMethod(testBean, "varOverloadEcho", 17, 23, 42)); + } + + @Test + public void testInvokeExactMethod() throws Exception { + assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", + (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); + assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo")); + assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", + (Object[]) null)); + assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo", + (Object[]) null, (Class[]) null)); + assertEquals("foo(String)", MethodUtils.invokeExactMethod(testBean, + "foo", "")); + assertEquals("foo(Object)", MethodUtils.invokeExactMethod(testBean, + "foo", new Object())); + assertEquals("foo(Integer)", MethodUtils.invokeExactMethod(testBean, + "foo", NumberUtils.INTEGER_ONE)); + assertEquals("foo(double)", MethodUtils.invokeExactMethod(testBean, + "foo", new Object[] { NumberUtils.DOUBLE_ONE }, + new Class[] { Double.TYPE })); + + try { + MethodUtils + .invokeExactMethod(testBean, "foo", NumberUtils.BYTE_ONE); + fail("should throw NoSuchMethodException"); + } catch (final NoSuchMethodException e) { + } + try { + MethodUtils + .invokeExactMethod(testBean, "foo", NumberUtils.LONG_ONE); + fail("should throw NoSuchMethodException"); + } catch (final NoSuchMethodException e) { + } + try { + MethodUtils.invokeExactMethod(testBean, "foo", Boolean.TRUE); + fail("should throw NoSuchMethodException"); + } catch (final NoSuchMethodException e) { + } + } + + @Test + public void testInvokeStaticMethod() throws Exception { + assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, + "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); + assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, + "bar", (Object[]) null)); + assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class, + "bar", (Object[]) null, (Class[]) null)); + assertEquals("bar(String)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", "")); + assertEquals("bar(Object)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", new Object())); + assertEquals("bar(Object)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", Boolean.TRUE)); + assertEquals("bar(Integer)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", NumberUtils.INTEGER_ONE)); + assertEquals("bar(int)", MethodUtils.invokeStaticMethod(TestBean.class, + "bar", NumberUtils.BYTE_ONE)); + assertEquals("bar(double)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", NumberUtils.LONG_ONE)); + assertEquals("bar(double)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", NumberUtils.DOUBLE_ONE)); + assertEquals("bar(String...)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", "a", "b")); + assertEquals("bar(int, String...)", MethodUtils.invokeStaticMethod( + TestBean.class, "bar", NumberUtils.INTEGER_ONE, "a", "b")); + + TestBean.verify(new ImmutablePair("String...", new String[]{"x", "y"}), + MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", "x", "y")); + TestBean.verify(new ImmutablePair("Number...", new Number[]{17, 23, 42}), + MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", 17, 23, 42)); + TestBean.verify(new ImmutablePair("String...", new String[]{"x", "y"}), + MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", "x", "y")); + TestBean.verify(new ImmutablePair("Number...", new Number[]{17, 23, 42}), + MethodUtils.invokeStaticMethod(TestBean.class, "varOverloadEchoStatic", 17, 23, 42)); + + try { + MethodUtils.invokeStaticMethod(TestBean.class, "does_not_exist"); + fail("should throw NoSuchMethodException"); + } catch (final NoSuchMethodException e) { + } + } + + @Test + public void testInvokeExactStaticMethod() throws Exception { + assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, + "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY)); + assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, + "bar", (Object[]) null)); + assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class, + "bar", (Object[]) null, (Class[]) null)); + assertEquals("bar(String)", MethodUtils.invokeExactStaticMethod( + TestBean.class, "bar", "")); + assertEquals("bar(Object)", MethodUtils.invokeExactStaticMethod( + TestBean.class, "bar", new Object())); + assertEquals("bar(Integer)", MethodUtils.invokeExactStaticMethod( + TestBean.class, "bar", NumberUtils.INTEGER_ONE)); + assertEquals("bar(double)", MethodUtils.invokeExactStaticMethod( + TestBean.class, "bar", new Object[] { NumberUtils.DOUBLE_ONE }, + new Class[] { Double.TYPE })); + + try { + MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", + NumberUtils.BYTE_ONE); + fail("should throw NoSuchMethodException"); + } catch (final NoSuchMethodException e) { + } + try { + MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", + NumberUtils.LONG_ONE); + fail("should throw NoSuchMethodException"); + } catch (final NoSuchMethodException e) { + } + try { + MethodUtils.invokeExactStaticMethod(TestBean.class, "bar", + Boolean.TRUE); + fail("should throw NoSuchMethodException"); + } catch (final NoSuchMethodException e) { + } + } + + @Test + public void testGetAccessibleInterfaceMethod() throws Exception { + final Class[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null }; + for (final Class[] element : p) { + final Method method = TestMutable.class.getMethod("getValue", element); + final Method accessibleMethod = MethodUtils.getAccessibleMethod(method); + assertNotSame(accessibleMethod, method); + assertSame(Mutable.class, accessibleMethod.getDeclaringClass()); + } + } + + @Test + public void testGetAccessibleMethodPrivateInterface() throws Exception { + final Method expected = TestBeanWithInterfaces.class.getMethod("foo"); + assertNotNull(expected); + final Method actual = MethodUtils.getAccessibleMethod(TestBeanWithInterfaces.class, "foo"); + assertNull(actual); + } + + @Test + public void testGetAccessibleInterfaceMethodFromDescription() + throws Exception { + final Class[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null }; + for (final Class[] element : p) { + final Method accessibleMethod = MethodUtils.getAccessibleMethod( + TestMutable.class, "getValue", element); + assertSame(Mutable.class, accessibleMethod.getDeclaringClass()); + } + } + + @Test + public void testGetAccessiblePublicMethod() throws Exception { + assertSame(MutableObject.class, MethodUtils.getAccessibleMethod( + MutableObject.class.getMethod("getValue", + ArrayUtils.EMPTY_CLASS_ARRAY)).getDeclaringClass()); + } + + @Test + public void testGetAccessiblePublicMethodFromDescription() throws Exception { + assertSame(MutableObject.class, MethodUtils.getAccessibleMethod( + MutableObject.class, "getValue", ArrayUtils.EMPTY_CLASS_ARRAY) + .getDeclaringClass()); + } + + @Test + public void testGetAccessibleMethodInaccessible() throws Exception { + final Method expected = TestBean.class.getDeclaredMethod("privateStuff"); + final Method actual = MethodUtils.getAccessibleMethod(expected); + assertNull(actual); + } + + @Test + public void testGetMatchingAccessibleMethod() throws Exception { + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + null, ArrayUtils.EMPTY_CLASS_ARRAY); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(String.class), singletonArray(String.class)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Object.class), singletonArray(Object.class)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Boolean.class), singletonArray(Object.class)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Byte.class), singletonArray(Integer.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Byte.TYPE), singletonArray(Integer.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Short.class), singletonArray(Integer.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Short.TYPE), singletonArray(Integer.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Character.class), singletonArray(Integer.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Character.TYPE), singletonArray(Integer.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Integer.class), singletonArray(Integer.class)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Integer.TYPE), singletonArray(Integer.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Long.class), singletonArray(Double.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Long.TYPE), singletonArray(Double.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Float.class), singletonArray(Double.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Float.TYPE), singletonArray(Double.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Double.class), singletonArray(Double.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Double.TYPE), singletonArray(Double.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + singletonArray(Double.TYPE), singletonArray(Double.TYPE)); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + new Class[] {String.class, String.class}, new Class[] {String[].class}); + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo", + new Class[] {Integer.TYPE, String.class, String.class}, new Class[] {Integer.class, String[].class}); + expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne", + singletonArray(ParentObject.class), singletonArray(ParentObject.class)); + expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne", + singletonArray(ChildObject.class), singletonArray(ParentObject.class)); + expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo", + singletonArray(ParentObject.class), singletonArray(GrandParentObject.class)); + expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo", + singletonArray(ChildObject.class), singletonArray(ChildInterface.class)); + } + + @Test + public void testNullArgument() { + expectMatchingAccessibleMethodParameterTypes(TestBean.class, "oneParameter", + singletonArray(null), singletonArray(String.class)); + } + + @Test + public void testGetOverrideHierarchyIncludingInterfaces() { + final Method method = MethodUtils.getAccessibleMethod(StringParameterizedChild.class, "consume", String.class); + final Iterator expected = + Arrays.asList(new MethodDescriptor(StringParameterizedChild.class, "consume", String.class), + new MethodDescriptor(GenericParent.class, "consume", GenericParent.class.getTypeParameters()[0]), + new MethodDescriptor(GenericConsumer.class, "consume", GenericConsumer.class.getTypeParameters()[0])) + .iterator(); + for (final Method m : MethodUtils.getOverrideHierarchy(method, Interfaces.INCLUDE)) { + assertTrue(expected.hasNext()); + final MethodDescriptor md = expected.next(); + assertEquals(md.declaringClass, m.getDeclaringClass()); + assertEquals(md.name, m.getName()); + assertEquals(md.parameterTypes.length, m.getParameterTypes().length); + for (int i = 0; i < md.parameterTypes.length; i++) { + assertTrue(TypeUtils.equals(md.parameterTypes[i], m.getGenericParameterTypes()[i])); + } + } + assertFalse(expected.hasNext()); + } + + @Test + public void testGetOverrideHierarchyExcludingInterfaces() { + final Method method = MethodUtils.getAccessibleMethod(StringParameterizedChild.class, "consume", String.class); + final Iterator expected = + Arrays.asList(new MethodDescriptor(StringParameterizedChild.class, "consume", String.class), + new MethodDescriptor(GenericParent.class, "consume", GenericParent.class.getTypeParameters()[0])) + .iterator(); + for (final Method m : MethodUtils.getOverrideHierarchy(method, Interfaces.EXCLUDE)) { + assertTrue(expected.hasNext()); + final MethodDescriptor md = expected.next(); + assertEquals(md.declaringClass, m.getDeclaringClass()); + assertEquals(md.name, m.getName()); + assertEquals(md.parameterTypes.length, m.getParameterTypes().length); + for (int i = 0; i < md.parameterTypes.length; i++) { + assertTrue(TypeUtils.equals(md.parameterTypes[i], m.getGenericParameterTypes()[i])); + } + } + assertFalse(expected.hasNext()); + } + + @Test + @Annotated + public void testGetMethodsWithAnnotation() throws NoSuchMethodException { + assertArrayEquals(new Method[0], MethodUtils.getMethodsWithAnnotation(Object.class, Annotated.class)); + + Method[] methodsWithAnnotation = MethodUtils.getMethodsWithAnnotation(MethodUtilsTest.class, Annotated.class); + assertEquals(2, methodsWithAnnotation.length); + assertThat(methodsWithAnnotation, hasItemInArray(MethodUtilsTest.class.getMethod("testGetMethodsWithAnnotation"))); + assertThat(methodsWithAnnotation, hasItemInArray(MethodUtilsTest.class.getMethod("testGetMethodsListWithAnnotation"))); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetMethodsWithAnnotationIllegalArgumentException1() { + MethodUtils.getMethodsWithAnnotation(FieldUtilsTest.class, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetMethodsWithAnnotationIllegalArgumentException2() { + MethodUtils.getMethodsWithAnnotation(null, Annotated.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetMethodsWithAnnotationIllegalArgumentException3() { + MethodUtils.getMethodsWithAnnotation(null, null); + } + + @Test + @Annotated + public void testGetMethodsListWithAnnotation() throws NoSuchMethodException { + assertEquals(0, MethodUtils.getMethodsListWithAnnotation(Object.class, Annotated.class).size()); + + final List methodWithAnnotation = MethodUtils.getMethodsListWithAnnotation(MethodUtilsTest.class, Annotated.class); + assertEquals(2, methodWithAnnotation.size()); + assertThat(methodWithAnnotation, hasItems( + MethodUtilsTest.class.getMethod("testGetMethodsWithAnnotation"), + MethodUtilsTest.class.getMethod("testGetMethodsListWithAnnotation") + )); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetMethodsListWithAnnotationIllegalArgumentException1() { + MethodUtils.getMethodsListWithAnnotation(FieldUtilsTest.class, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetMethodsListWithAnnotationIllegalArgumentException2() { + MethodUtils.getMethodsListWithAnnotation(null, Annotated.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetMethodsListWithAnnotationIllegalArgumentException3() { + MethodUtils.getMethodsListWithAnnotation(null, null); + } + +private void expectMatchingAccessibleMethodParameterTypes(final java.lang.Class cls, final java.lang.String methodName, final java.lang.Class[] requestTypes, final java.lang.Class[] actualTypes) { + final java.lang.reflect.Method m = org.apache.commons.lang3.reflect.MethodUtils.getMatchingAccessibleMethod(cls, methodName, /* NPEX_NULL_EXP */ + requestTypes); + Assert.assertNotNull(((("could not find any matches for " + methodName) + " (") + toString(requestTypes)) + ")", m); + Assert.assertTrue((toString(m.getParameterTypes()) + " not equals ") + toString(actualTypes), java.util.Arrays.equals(actualTypes, m.getParameterTypes())); +} + + private String toString(final Class[] c) { + return Arrays.asList(c).toString(); + } + + private Class[] singletonArray(final Class c) { + Class[] result = classCache.get(c); + if (result == null) { + result = new Class[] { c }; + classCache.put(c, result); + } + return result; + } + + public static class InheritanceBean { + public void testOne(final Object obj) {} + public void testOne(final GrandParentObject obj) {} + public void testOne(final ParentObject obj) {} + public void testTwo(final Object obj) {} + public void testTwo(final GrandParentObject obj) {} + public void testTwo(final ChildInterface obj) {} + } + + interface ChildInterface {} + public static class GrandParentObject {} + public static class ParentObject extends GrandParentObject {} + public static class ChildObject extends ParentObject implements ChildInterface {} + + private static class MethodDescriptor { + final Class declaringClass; + final String name; + final Type[] parameterTypes; + + MethodDescriptor(final Class declaringClass, final String name, final Type... parameterTypes) { + this.declaringClass = declaringClass; + this.name = name; + this.parameterTypes = parameterTypes; + } + } + + @Test + public void testVarArgsUnboxing() throws Exception { + TestBean testBean = new TestBean(); + int[] actual = (int[])MethodUtils.invokeMethod(testBean, "unboxing", Integer.valueOf(1), Integer.valueOf(2)); + Assert.assertArrayEquals(new int[]{1, 2}, actual); + } + + @Test + public void testInvokeMethodForceAccessNoArgs() throws Exception { + Method privateStringStuffMethod = MethodUtils.getMatchingMethod(TestBean.class, "privateStringStuff"); + Assert.assertFalse(privateStringStuffMethod.isAccessible()); + Assert.assertEquals("privateStringStuff()", MethodUtils.invokeMethod(testBean, true, "privateStringStuff")); + Assert.assertFalse(privateStringStuffMethod.isAccessible()); + } + + @Test + public void testInvokeMethodForceAccessWithArgs() throws Exception { + Assert.assertEquals("privateStringStuff(Integer)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", 5)); + Assert.assertEquals("privateStringStuff(double)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", 5.0d)); + Assert.assertEquals("privateStringStuff(String)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", "Hi There")); + Assert.assertEquals("privateStringStuff(Object)", MethodUtils.invokeMethod(testBean, true, "privateStringStuff", new Date())); + } + + @Test + public void testDistance() throws Exception { + Method distanceMethod = MethodUtils.getMatchingMethod(MethodUtils.class, "distance", Class[].class, Class[].class); + distanceMethod.setAccessible(true); + + Assert.assertEquals(-1, distanceMethod.invoke(null, new Class[]{String.class}, new Class[]{Date.class})); + Assert.assertEquals(0, distanceMethod.invoke(null, new Class[]{Date.class}, new Class[]{Date.class})); + Assert.assertEquals(1, distanceMethod.invoke(null, new Class[]{Integer.class}, new Class[]{ClassUtils.wrapperToPrimitive(Integer.class)})); + Assert.assertEquals(2, distanceMethod.invoke(null, new Class[]{Integer.class}, new Class[]{Object.class})); + + distanceMethod.setAccessible(false); + } +} diff --git a/Java/commons-lang-MethodUtilsTest_711/metadata.json b/Java/commons-lang-MethodUtilsTest_711/metadata.json new file mode 100644 index 000000000..3be27ee5b --- /dev/null +++ b/Java/commons-lang-MethodUtilsTest_711/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MethodUtilsTest_711", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn clean test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java", + "line": 709, + "npe_method": "expectMatchingAccessibleMethodParameterTypes", + "deref_field": "requestTypes", + "npe_class": "MethodUtilsTest", + "repo": "commons-lang", + "bug_id": "MethodUtilsTest_711" + } +} diff --git a/Java/commons-lang-MethodUtilsTest_711/npe.json b/Java/commons-lang-MethodUtilsTest_711/npe.json new file mode 100644 index 000000000..09c31736a --- /dev/null +++ b/Java/commons-lang-MethodUtilsTest_711/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java", + "line": 709, + "npe_method": "expectMatchingAccessibleMethodParameterTypes", + "deref_field": "requestTypes", + "npe_class": "MethodUtilsTest" +} \ No newline at end of file diff --git a/Java/commons-lang-MethodUtils_229/Dockerfile b/Java/commons-lang-MethodUtils_229/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MethodUtils_229/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MethodUtils_229/buggy.java b/Java/commons-lang-MethodUtils_229/buggy.java new file mode 100644 index 000000000..5ed5c3fdb --- /dev/null +++ b/Java/commons-lang-MethodUtils_229/buggy.java @@ -0,0 +1,885 @@ +/* + * 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.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.Validate; + +/** + *

Utility reflection methods focused on {@link Method}s, originally from Commons BeanUtils. + * Differences from the BeanUtils version may be noted, especially where similar functionality + * already existed within Lang. + *

+ * + *

Known Limitations

+ *

Accessing Public Methods In A Default Access Superclass

+ *

There is an issue when invoking {@code public} methods contained in a default access superclass on JREs prior to 1.4. + * Reflection locates these methods fine and correctly assigns them as {@code public}. + * However, an {@link IllegalAccessException} is thrown if the method is invoked.

+ * + *

{@link MethodUtils} contains a workaround for this situation. + * It will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this method. + * If this call succeeds, then the method can be invoked as normal. + * This call will only succeed when the application has sufficient security privileges. + * If this call fails then the method may fail.

+ * + * @since 2.5 + */ +public class MethodUtils { + + /** + *

{@link MethodUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

+ * + *

This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

+ */ + public MethodUtils() { + super(); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.4 + */ + public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, forceAccess, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * @since 3.5 + */ +/** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object + * invoke method on this object + * @param forceAccess + * force access to invoke method even if it's not accessible + * @param methodName + * get method with this name + * @param args + * use these arguments - treat null as empty array + * @param parameterTypes + * match these parameters - treat null as empty array + * @return The value returned by the invoked method + * @throws NoSuchMethodException + * if there is no such accessible method + * @throws InvocationTargetException + * wraps an exception thrown by the method invoked + * @throws IllegalAccessException + * if the requested method is not accessible via reflection + * @since 3.5 + */ +public static java.lang.Object invokeMethod(final java.lang.Object object, final boolean forceAccess, final java.lang.String methodName, java.lang.Object[] args, java.lang.Class[] parameterTypes) throws java.lang.NoSuchMethodException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException { + parameterTypes = org.apache.commons.lang3.ArrayUtils.nullToEmpty(parameterTypes); + args = org.apache.commons.lang3.ArrayUtils.nullToEmpty(args); + final java.lang.String messagePrefix; + java.lang.reflect.Method method = null; + boolean isOriginallyAccessible = false; + java.lang.Object result = null; + try { + if (forceAccess) { + messagePrefix = "No such method: "; + method = org.apache.commons.lang3.reflect.MethodUtils.getMatchingMethod(object.getClass(), methodName, parameterTypes); + if (method != null) { + isOriginallyAccessible = method.isAccessible(); + if (!isOriginallyAccessible) { + method.setAccessible(true); + } + } + } else { + messagePrefix = "No such accessible method: "; + method = org.apache.commons.lang3.reflect.MethodUtils.getMatchingAccessibleMethod(object.getClass(), methodName, parameterTypes); + } + { + args = org.apache.commons.lang3.reflect.MethodUtils.toVarArgs(/* NPEX_NULL_EXP */ + method, args); + result = method.invoke(object, args); + } + } finally { + if (((method != null) && forceAccess) && (method.isAccessible() != isOriginallyAccessible)) { + method.setAccessible(isOriginallyAccessible); + } + } + return result; +} + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + return invokeMethod(object, false, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + * + * @since 3.4 + */ + public static Object invokeExactMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a method with no parameters.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(object.getClass(), methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on object: " + + object.getClass().getName()); + } + return method.invoke(object, args); + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(cls, methodName, parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + return method.invoke(null, args); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeStaticMethod(Class, String, Object[], Class[])}. + *

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getMatchingAccessibleMethod(cls, methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + args = toVarArgs(method, args); + return method.invoke(null, args); + } + + private static Object[] toVarArgs(Method method, Object[] args) { + if (method.isVarArgs()) { + Class[] methodParameterTypes = method.getParameterTypes(); + args = getVarArgs(args, methodParameterTypes); + } + return args; + } + + /** + *

Given an arguments array passed to a varargs method, return an array of arguments in the canonical form, + * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type. + *

+ * + * @param args the array of arguments passed to the varags method + * @param methodParameterTypes the declared array of method parameter types + * @return an array of the variadic arguments passed to the method + * @since 3.5 + */ + static Object[] getVarArgs(Object[] args, Class[] methodParameterTypes) { + if (args.length == methodParameterTypes.length + && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) { + // The args array is already in the canonical form for the method. + return args; + } + + // Construct a new array matching the method's declared parameter types. + Object[] newArgs = new Object[methodParameterTypes.length]; + + // Copy the normal (non-varargs) parameters + System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1); + + // Construct a new array for the variadic parameters + Class varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + int varArgLength = args.length - methodParameterTypes.length + 1; + + Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength); + // Copy the variadic arguments into the varargs array. + System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength); + + if(varArgComponentType.isPrimitive()) { + // unbox from wrapper type to primitive type + varArgsArray = ArrayUtils.toPrimitive(varArgsArray); + } + + // Store the varargs array in the last position of the array to return + newArgs[methodParameterTypes.length - 1] = varArgsArray; + + // Return the canonical varargs array. + return newArgs; + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) with given name and parameters. If no such method + * can be found, return {@code null}. + * This is just a convenience wrapper for + * {@link #getAccessibleMethod(Method)}.

+ * + * @param cls get method from this class + * @param methodName get method with this name + * @param parameterTypes with these parameters types + * @return The accessible method + */ + public static Method getAccessibleMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + try { + return getAccessibleMethod(cls.getMethod(methodName, + parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return {@code null}.

+ * + * @param method The method that we wish to call + * @return The accessible method + */ + public static Method getAccessibleMethod(Method method) { + if (!MemberUtils.isAccessible(method)) { + return null; + } + // If the declaring class is public, we are done + final Class cls = method.getDeclaringClass(); + if (Modifier.isPublic(cls.getModifiers())) { + return method; + } + final String methodName = method.getName(); + final Class[] parameterTypes = method.getParameterTypes(); + + // Check the implemented interfaces and subinterfaces + method = getAccessibleMethodFromInterfaceNest(cls, methodName, + parameterTypes); + + // Check the superclass chain + if (method == null) { + method = getAccessibleMethodFromSuperclass(cls, methodName, + parameterTypes); + } + return method; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) by scanning through the superclasses. If no such method + * can be found, return {@code null}.

+ * + * @param cls Class to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromSuperclass(final Class cls, + final String methodName, final Class... parameterTypes) { + Class parentClass = cls.getSuperclass(); + while (parentClass != null) { + if (Modifier.isPublic(parentClass.getModifiers())) { + try { + return parentClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException e) { + return null; + } + } + parentClass = parentClass.getSuperclass(); + } + return null; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such method + * can be found, return {@code null}.

+ * + *

There isn't any good reason why this method must be {@code private}. + * It is because there doesn't seem any reason why other classes should + * call this rather than the higher level methods.

+ * + * @param cls Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromInterfaceNest(Class cls, + final String methodName, final Class... parameterTypes) { + // Search up the superclass chain + for (; cls != null; cls = cls.getSuperclass()) { + + // Check the implemented interfaces of the parent class + final Class[] interfaces = cls.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + return interfaces[i].getDeclaredMethod(methodName, + parameterTypes); + } catch (final NoSuchMethodException e) { // NOPMD + /* + * Swallow, if no method is found after the loop then this + * method returns null. + */ + } + // Recursively check our parent interfaces + final Method method = getAccessibleMethodFromInterfaceNest(interfaces[i], + methodName, parameterTypes); + if (method != null) { + return method; + } + } + } + return null; + } + + /** + *

Finds an accessible method that matches the given name and has compatible parameters. + * Compatible parameters mean that every method parameter is assignable from + * the given parameters. + * In other words, it finds a method with the given name + * that will take the parameters given.

+ * + *

This method is used by + * {@link + * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + *

This method can match primitive parameter by passing in wrapper classes. + * For example, a {@code Boolean} will match a primitive {@code boolean} + * parameter. + *

+ * + * @param cls find method in this class + * @param methodName find method with this name + * @param parameterTypes find method with most compatible parameters + * @return The accessible method + */ + public static Method getMatchingAccessibleMethod(final Class cls, + final String methodName, final Class... parameterTypes) { + try { + final Method method = cls.getMethod(methodName, parameterTypes); + MemberUtils.setAccessibleWorkaround(method); + return method; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception + } + // search through all methods + Method bestMatch = null; + final Method[] methods = cls.getMethods(); + for (final Method method : methods) { + // compare name and parameters + if (method.getName().equals(methodName) && + MemberUtils.isMatchingMethod(method, parameterTypes)) { + // get accessible version of method + final Method accessibleMethod = getAccessibleMethod(method); + if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit( + accessibleMethod, + bestMatch, + parameterTypes) < 0)) { + bestMatch = accessibleMethod; + } + } + } + if (bestMatch != null) { + MemberUtils.setAccessibleWorkaround(bestMatch); + } + return bestMatch; + } + + /** + *

Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

+ * @param cls The class that will be subjected to the method search + * @param methodName The method that we wish to call + * @param parameterTypes Argument class types + * @return The method + * + * @since 3.5 + */ + public static Method getMatchingMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + Validate.notNull(cls, "Null class not allowed."); + Validate.notEmpty(methodName, "Null or blank methodName not allowed."); + + // Address methods in superclasses + Method[] methodArray = cls.getDeclaredMethods(); + List> superclassList = ClassUtils.getAllSuperclasses(cls); + for (Class klass : superclassList) { + methodArray = ArrayUtils.addAll(methodArray, klass.getDeclaredMethods()); + } + + Method inexactMatch = null; + for (Method method : methodArray) { + if (methodName.equals(method.getName()) && + ArrayUtils.isEquals(parameterTypes, method.getParameterTypes())) { + return method; + } else if (methodName.equals(method.getName()) && + ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { + if (inexactMatch == null) { + inexactMatch = method; + } else if (distance(parameterTypes, method.getParameterTypes()) + < distance(parameterTypes, inexactMatch.getParameterTypes())) { + inexactMatch = method; + } + } + + } + return inexactMatch; + } + + /** + *

Returns the aggregate number of inheritance hops between assignable argument class types. Returns -1 + * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.

+ * @param classArray + * @param toClassArray + * @return the aggregate number of inheritance hops between assignable argument class types. + */ + private static int distance(Class[] classArray, Class[] toClassArray) { + int answer = 0; + + if (!ClassUtils.isAssignable(classArray, toClassArray, true)) { + return -1; + } + for (int offset = 0; offset < classArray.length; offset++) { + // Note InheritanceUtils.distance() uses different scoring system. + if (classArray[offset].equals(toClassArray[offset])) { + continue; + } else if (ClassUtils.isAssignable(classArray[offset], toClassArray[offset], true) + && !ClassUtils.isAssignable(classArray[offset], toClassArray[offset], false)) { + answer++; + } else { + answer = answer + 2; + } + } + + return answer; + } + + /** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * @param method lowest to consider + * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException if the specified method is {@code null} + * @since 3.2 + */ + public static Set getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { + Validate.notNull(method); + final Set result = new LinkedHashSet(); + result.add(method); + + final Class[] parameterTypes = method.getParameterTypes(); + + final Class declaringClass = method.getDeclaringClass(); + + final Iterator> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); + //skip the declaring class :P + hierarchy.next(); + hierarchyTraversal: while (hierarchy.hasNext()) { + final Class c = hierarchy.next(); + final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); + if (m == null) { + continue; + } + if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { + // matches without generics + result.add(m); + continue; + } + // necessary to get arguments every time in the case that we are including interfaces + final Map, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); + for (int i = 0; i < parameterTypes.length; i++) { + final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); + final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); + if (!TypeUtils.equals(childType, parentType)) { + continue hierarchyTraversal; + } + } + result.add(m); + } + return result; + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched + * @return an array of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Method[] getMethodsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls); + return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]); + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a method to be matched + * @return a list of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getMethodsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final Method[] allMethods = cls.getMethods(); + final List annotatedMethods = new ArrayList(); + for (final Method method : allMethods) { + if (method.getAnnotation(annotationCls) != null) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + +} diff --git a/Java/commons-lang-MethodUtils_229/metadata.json b/Java/commons-lang-MethodUtils_229/metadata.json new file mode 100644 index 000000000..cf865ec4f --- /dev/null +++ b/Java/commons-lang-MethodUtils_229/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MethodUtils_229", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 249, + "npe_method": "invokeMethod", + "deref_field": "method", + "npe_class": "MethodUtils", + "repo": "commons-lang", + "bug_id": "MethodUtils_229" + } +} diff --git a/Java/commons-lang-MethodUtils_229/npe.json b/Java/commons-lang-MethodUtils_229/npe.json new file mode 100644 index 000000000..415479ec6 --- /dev/null +++ b/Java/commons-lang-MethodUtils_229/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 249, + "npe_method": "invokeMethod", + "deref_field": "method", + "npe_class": "MethodUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-MethodUtils_349/Dockerfile b/Java/commons-lang-MethodUtils_349/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MethodUtils_349/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MethodUtils_349/buggy.java b/Java/commons-lang-MethodUtils_349/buggy.java new file mode 100644 index 000000000..eb691f8b6 --- /dev/null +++ b/Java/commons-lang-MethodUtils_349/buggy.java @@ -0,0 +1,891 @@ +/* + * 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.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.Validate; + +/** + *

Utility reflection methods focused on {@link Method}s, originally from Commons BeanUtils. + * Differences from the BeanUtils version may be noted, especially where similar functionality + * already existed within Lang. + *

+ * + *

Known Limitations

+ *

Accessing Public Methods In A Default Access Superclass

+ *

There is an issue when invoking {@code public} methods contained in a default access superclass on JREs prior to 1.4. + * Reflection locates these methods fine and correctly assigns them as {@code public}. + * However, an {@link IllegalAccessException} is thrown if the method is invoked.

+ * + *

{@link MethodUtils} contains a workaround for this situation. + * It will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this method. + * If this call succeeds, then the method can be invoked as normal. + * This call will only succeed when the application has sufficient security privileges. + * If this call fails then the method may fail.

+ * + * @since 2.5 + */ +public class MethodUtils { + + /** + *

{@link MethodUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

+ * + *

This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

+ */ + public MethodUtils() { + super(); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.4 + */ + public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, forceAccess, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + args = ArrayUtils.nullToEmpty(args); + + final String messagePrefix; + Method method = null; + boolean isOriginallyAccessible = false; + Object result = null; + + try { + if (forceAccess) { + messagePrefix = "No such method: "; + method = getMatchingMethod(object.getClass(), + methodName, parameterTypes); + if (method != null) { + isOriginallyAccessible = method.isAccessible(); + if (!isOriginallyAccessible) { + method.setAccessible(true); + } + } + } else { + messagePrefix = "No such accessible method: "; + method = getMatchingAccessibleMethod(object.getClass(), + methodName, parameterTypes); + } + + if (method == null) { + throw new NoSuchMethodException(messagePrefix + + methodName + "() on object: " + + object.getClass().getName()); + } + args = toVarArgs(method, args); + + result = method.invoke(object, args); + } + finally { + if (method != null && forceAccess && method.isAccessible() != isOriginallyAccessible) { + method.setAccessible(isOriginallyAccessible); + } + } + + return result; + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + return invokeMethod(object, false, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + * + * @since 3.4 + */ + public static Object invokeExactMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a method with no parameters.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ +/** + *

Invokes a method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

+ * + * @param object + * invoke method on this object + * @param methodName + * get method with this name + * @param args + * use these arguments - treat null as empty array + * @param parameterTypes + * match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * @throws NoSuchMethodException + * if there is no such accessible method + * @throws InvocationTargetException + * wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException + * if the requested method is not accessible + * via reflection + */ +public static java.lang.Object invokeExactMethod(final java.lang.Object object, final java.lang.String methodName, java.lang.Object[] args, java.lang.Class[] parameterTypes) throws java.lang.NoSuchMethodException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException { + args = org.apache.commons.lang3.ArrayUtils.nullToEmpty(args); + parameterTypes = org.apache.commons.lang3.ArrayUtils.nullToEmpty(parameterTypes); + final java.lang.reflect.Method method = org.apache.commons.lang3.reflect.MethodUtils.getAccessibleMethod(object.getClass(), methodName, parameterTypes); + { + return /* NPEX_NULL_EXP */ + method.invoke(object, args); + } +} + + /** + *

Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(cls, methodName, parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + return method.invoke(null, args); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeStaticMethod(Class, String, Object[], Class[])}. + *

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getMatchingAccessibleMethod(cls, methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + args = toVarArgs(method, args); + return method.invoke(null, args); + } + + private static Object[] toVarArgs(Method method, Object[] args) { + if (method.isVarArgs()) { + Class[] methodParameterTypes = method.getParameterTypes(); + args = getVarArgs(args, methodParameterTypes); + } + return args; + } + + /** + *

Given an arguments array passed to a varargs method, return an array of arguments in the canonical form, + * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type. + *

+ * + * @param args the array of arguments passed to the varags method + * @param methodParameterTypes the declared array of method parameter types + * @return an array of the variadic arguments passed to the method + * @since 3.5 + */ + static Object[] getVarArgs(Object[] args, Class[] methodParameterTypes) { + if (args.length == methodParameterTypes.length + && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) { + // The args array is already in the canonical form for the method. + return args; + } + + // Construct a new array matching the method's declared parameter types. + Object[] newArgs = new Object[methodParameterTypes.length]; + + // Copy the normal (non-varargs) parameters + System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1); + + // Construct a new array for the variadic parameters + Class varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + int varArgLength = args.length - methodParameterTypes.length + 1; + + Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength); + // Copy the variadic arguments into the varargs array. + System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength); + + if(varArgComponentType.isPrimitive()) { + // unbox from wrapper type to primitive type + varArgsArray = ArrayUtils.toPrimitive(varArgsArray); + } + + // Store the varargs array in the last position of the array to return + newArgs[methodParameterTypes.length - 1] = varArgsArray; + + // Return the canonical varargs array. + return newArgs; + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) with given name and parameters. If no such method + * can be found, return {@code null}. + * This is just a convenience wrapper for + * {@link #getAccessibleMethod(Method)}.

+ * + * @param cls get method from this class + * @param methodName get method with this name + * @param parameterTypes with these parameters types + * @return The accessible method + */ + public static Method getAccessibleMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + try { + return getAccessibleMethod(cls.getMethod(methodName, + parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return {@code null}.

+ * + * @param method The method that we wish to call + * @return The accessible method + */ + public static Method getAccessibleMethod(Method method) { + if (!MemberUtils.isAccessible(method)) { + return null; + } + // If the declaring class is public, we are done + final Class cls = method.getDeclaringClass(); + if (Modifier.isPublic(cls.getModifiers())) { + return method; + } + final String methodName = method.getName(); + final Class[] parameterTypes = method.getParameterTypes(); + + // Check the implemented interfaces and subinterfaces + method = getAccessibleMethodFromInterfaceNest(cls, methodName, + parameterTypes); + + // Check the superclass chain + if (method == null) { + method = getAccessibleMethodFromSuperclass(cls, methodName, + parameterTypes); + } + return method; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) by scanning through the superclasses. If no such method + * can be found, return {@code null}.

+ * + * @param cls Class to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromSuperclass(final Class cls, + final String methodName, final Class... parameterTypes) { + Class parentClass = cls.getSuperclass(); + while (parentClass != null) { + if (Modifier.isPublic(parentClass.getModifiers())) { + try { + return parentClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException e) { + return null; + } + } + parentClass = parentClass.getSuperclass(); + } + return null; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such method + * can be found, return {@code null}.

+ * + *

There isn't any good reason why this method must be {@code private}. + * It is because there doesn't seem any reason why other classes should + * call this rather than the higher level methods.

+ * + * @param cls Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromInterfaceNest(Class cls, + final String methodName, final Class... parameterTypes) { + // Search up the superclass chain + for (; cls != null; cls = cls.getSuperclass()) { + + // Check the implemented interfaces of the parent class + final Class[] interfaces = cls.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + return interfaces[i].getDeclaredMethod(methodName, + parameterTypes); + } catch (final NoSuchMethodException e) { // NOPMD + /* + * Swallow, if no method is found after the loop then this + * method returns null. + */ + } + // Recursively check our parent interfaces + final Method method = getAccessibleMethodFromInterfaceNest(interfaces[i], + methodName, parameterTypes); + if (method != null) { + return method; + } + } + } + return null; + } + + /** + *

Finds an accessible method that matches the given name and has compatible parameters. + * Compatible parameters mean that every method parameter is assignable from + * the given parameters. + * In other words, it finds a method with the given name + * that will take the parameters given.

+ * + *

This method is used by + * {@link + * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + *

This method can match primitive parameter by passing in wrapper classes. + * For example, a {@code Boolean} will match a primitive {@code boolean} + * parameter. + *

+ * + * @param cls find method in this class + * @param methodName find method with this name + * @param parameterTypes find method with most compatible parameters + * @return The accessible method + */ + public static Method getMatchingAccessibleMethod(final Class cls, + final String methodName, final Class... parameterTypes) { + try { + final Method method = cls.getMethod(methodName, parameterTypes); + MemberUtils.setAccessibleWorkaround(method); + return method; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception + } + // search through all methods + Method bestMatch = null; + final Method[] methods = cls.getMethods(); + for (final Method method : methods) { + // compare name and parameters + if (method.getName().equals(methodName) && + MemberUtils.isMatchingMethod(method, parameterTypes)) { + // get accessible version of method + final Method accessibleMethod = getAccessibleMethod(method); + if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit( + accessibleMethod, + bestMatch, + parameterTypes) < 0)) { + bestMatch = accessibleMethod; + } + } + } + if (bestMatch != null) { + MemberUtils.setAccessibleWorkaround(bestMatch); + } + return bestMatch; + } + + /** + *

Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

+ * @param cls The class that will be subjected to the method search + * @param methodName The method that we wish to call + * @param parameterTypes Argument class types + * @return The method + * + * @since 3.5 + */ + public static Method getMatchingMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + Validate.notNull(cls, "Null class not allowed."); + Validate.notEmpty(methodName, "Null or blank methodName not allowed."); + + // Address methods in superclasses + Method[] methodArray = cls.getDeclaredMethods(); + List> superclassList = ClassUtils.getAllSuperclasses(cls); + for (Class klass : superclassList) { + methodArray = ArrayUtils.addAll(methodArray, klass.getDeclaredMethods()); + } + + Method inexactMatch = null; + for (Method method : methodArray) { + if (methodName.equals(method.getName()) && + ArrayUtils.isEquals(parameterTypes, method.getParameterTypes())) { + return method; + } else if (methodName.equals(method.getName()) && + ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { + if (inexactMatch == null) { + inexactMatch = method; + } else if (distance(parameterTypes, method.getParameterTypes()) + < distance(parameterTypes, inexactMatch.getParameterTypes())) { + inexactMatch = method; + } + } + + } + return inexactMatch; + } + + /** + *

Returns the aggregate number of inheritance hops between assignable argument class types. Returns -1 + * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.

+ * @param classArray + * @param toClassArray + * @return the aggregate number of inheritance hops between assignable argument class types. + */ + private static int distance(Class[] classArray, Class[] toClassArray) { + int answer = 0; + + if (!ClassUtils.isAssignable(classArray, toClassArray, true)) { + return -1; + } + for (int offset = 0; offset < classArray.length; offset++) { + // Note InheritanceUtils.distance() uses different scoring system. + if (classArray[offset].equals(toClassArray[offset])) { + continue; + } else if (ClassUtils.isAssignable(classArray[offset], toClassArray[offset], true) + && !ClassUtils.isAssignable(classArray[offset], toClassArray[offset], false)) { + answer++; + } else { + answer = answer + 2; + } + } + + return answer; + } + + /** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * @param method lowest to consider + * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException if the specified method is {@code null} + * @since 3.2 + */ + public static Set getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { + Validate.notNull(method); + final Set result = new LinkedHashSet(); + result.add(method); + + final Class[] parameterTypes = method.getParameterTypes(); + + final Class declaringClass = method.getDeclaringClass(); + + final Iterator> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); + //skip the declaring class :P + hierarchy.next(); + hierarchyTraversal: while (hierarchy.hasNext()) { + final Class c = hierarchy.next(); + final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); + if (m == null) { + continue; + } + if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { + // matches without generics + result.add(m); + continue; + } + // necessary to get arguments every time in the case that we are including interfaces + final Map, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); + for (int i = 0; i < parameterTypes.length; i++) { + final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); + final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); + if (!TypeUtils.equals(childType, parentType)) { + continue hierarchyTraversal; + } + } + result.add(m); + } + return result; + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched + * @return an array of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Method[] getMethodsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls); + return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]); + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a method to be matched + * @return a list of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getMethodsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final Method[] allMethods = cls.getMethods(); + final List annotatedMethods = new ArrayList(); + for (final Method method : allMethods) { + if (method.getAnnotation(annotationCls) != null) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + +} diff --git a/Java/commons-lang-MethodUtils_349/metadata.json b/Java/commons-lang-MethodUtils_349/metadata.json new file mode 100644 index 000000000..4a54398eb --- /dev/null +++ b/Java/commons-lang-MethodUtils_349/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MethodUtils_349", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 372, + "npe_method": "invokeExactMethod", + "deref_field": "method", + "npe_class": "MethodUtils", + "repo": "commons-lang", + "bug_id": "MethodUtils_349" + } +} diff --git a/Java/commons-lang-MethodUtils_349/npe.json b/Java/commons-lang-MethodUtils_349/npe.json new file mode 100644 index 000000000..d2613a7f0 --- /dev/null +++ b/Java/commons-lang-MethodUtils_349/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 372, + "npe_method": "invokeExactMethod", + "deref_field": "method", + "npe_class": "MethodUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-MethodUtils_383/Dockerfile b/Java/commons-lang-MethodUtils_383/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MethodUtils_383/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MethodUtils_383/buggy.java b/Java/commons-lang-MethodUtils_383/buggy.java new file mode 100644 index 000000000..5249b6bfc --- /dev/null +++ b/Java/commons-lang-MethodUtils_383/buggy.java @@ -0,0 +1,893 @@ +/* + * 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.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.Validate; + +/** + *

Utility reflection methods focused on {@link Method}s, originally from Commons BeanUtils. + * Differences from the BeanUtils version may be noted, especially where similar functionality + * already existed within Lang. + *

+ * + *

Known Limitations

+ *

Accessing Public Methods In A Default Access Superclass

+ *

There is an issue when invoking {@code public} methods contained in a default access superclass on JREs prior to 1.4. + * Reflection locates these methods fine and correctly assigns them as {@code public}. + * However, an {@link IllegalAccessException} is thrown if the method is invoked.

+ * + *

{@link MethodUtils} contains a workaround for this situation. + * It will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this method. + * If this call succeeds, then the method can be invoked as normal. + * This call will only succeed when the application has sufficient security privileges. + * If this call fails then the method may fail.

+ * + * @since 2.5 + */ +public class MethodUtils { + + /** + *

{@link MethodUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

+ * + *

This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

+ */ + public MethodUtils() { + super(); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.4 + */ + public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, forceAccess, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + args = ArrayUtils.nullToEmpty(args); + + final String messagePrefix; + Method method = null; + boolean isOriginallyAccessible = false; + Object result = null; + + try { + if (forceAccess) { + messagePrefix = "No such method: "; + method = getMatchingMethod(object.getClass(), + methodName, parameterTypes); + if (method != null) { + isOriginallyAccessible = method.isAccessible(); + if (!isOriginallyAccessible) { + method.setAccessible(true); + } + } + } else { + messagePrefix = "No such accessible method: "; + method = getMatchingAccessibleMethod(object.getClass(), + methodName, parameterTypes); + } + + if (method == null) { + throw new NoSuchMethodException(messagePrefix + + methodName + "() on object: " + + object.getClass().getName()); + } + args = toVarArgs(method, args); + + result = method.invoke(object, args); + } + finally { + if (method != null && forceAccess && method.isAccessible() != isOriginallyAccessible) { + method.setAccessible(isOriginallyAccessible); + } + } + + return result; + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + return invokeMethod(object, false, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + * + * @since 3.4 + */ + public static Object invokeExactMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a method with no parameters.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(object.getClass(), methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on object: " + + object.getClass().getName()); + } + return method.invoke(object, args); + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ +/** + *

Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls + * invoke static method on this class + * @param methodName + * get method with this name + * @param args + * use these arguments - treat {@code null} as empty array + * @param parameterTypes + * match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * @throws NoSuchMethodException + * if there is no such accessible method + * @throws InvocationTargetException + * wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException + * if the requested method is not accessible + * via reflection + */ +public static java.lang.Object invokeExactStaticMethod(final java.lang.Class cls, final java.lang.String methodName, java.lang.Object[] args, java.lang.Class[] parameterTypes) throws java.lang.NoSuchMethodException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException { + args = org.apache.commons.lang3.ArrayUtils.nullToEmpty(args); + parameterTypes = org.apache.commons.lang3.ArrayUtils.nullToEmpty(parameterTypes); + final java.lang.reflect.Method method = org.apache.commons.lang3.reflect.MethodUtils.getAccessibleMethod(cls, methodName, parameterTypes); + { + return /* NPEX_NULL_EXP */ + method.invoke(null, args); + } +} + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeStaticMethod(Class, String, Object[], Class[])}. + *

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getMatchingAccessibleMethod(cls, methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + args = toVarArgs(method, args); + return method.invoke(null, args); + } + + private static Object[] toVarArgs(Method method, Object[] args) { + if (method.isVarArgs()) { + Class[] methodParameterTypes = method.getParameterTypes(); + args = getVarArgs(args, methodParameterTypes); + } + return args; + } + + /** + *

Given an arguments array passed to a varargs method, return an array of arguments in the canonical form, + * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type. + *

+ * + * @param args the array of arguments passed to the varags method + * @param methodParameterTypes the declared array of method parameter types + * @return an array of the variadic arguments passed to the method + * @since 3.5 + */ + static Object[] getVarArgs(Object[] args, Class[] methodParameterTypes) { + if (args.length == methodParameterTypes.length + && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) { + // The args array is already in the canonical form for the method. + return args; + } + + // Construct a new array matching the method's declared parameter types. + Object[] newArgs = new Object[methodParameterTypes.length]; + + // Copy the normal (non-varargs) parameters + System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1); + + // Construct a new array for the variadic parameters + Class varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + int varArgLength = args.length - methodParameterTypes.length + 1; + + Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength); + // Copy the variadic arguments into the varargs array. + System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength); + + if(varArgComponentType.isPrimitive()) { + // unbox from wrapper type to primitive type + varArgsArray = ArrayUtils.toPrimitive(varArgsArray); + } + + // Store the varargs array in the last position of the array to return + newArgs[methodParameterTypes.length - 1] = varArgsArray; + + // Return the canonical varargs array. + return newArgs; + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) with given name and parameters. If no such method + * can be found, return {@code null}. + * This is just a convenience wrapper for + * {@link #getAccessibleMethod(Method)}.

+ * + * @param cls get method from this class + * @param methodName get method with this name + * @param parameterTypes with these parameters types + * @return The accessible method + */ + public static Method getAccessibleMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + try { + return getAccessibleMethod(cls.getMethod(methodName, + parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return {@code null}.

+ * + * @param method The method that we wish to call + * @return The accessible method + */ + public static Method getAccessibleMethod(Method method) { + if (!MemberUtils.isAccessible(method)) { + return null; + } + // If the declaring class is public, we are done + final Class cls = method.getDeclaringClass(); + if (Modifier.isPublic(cls.getModifiers())) { + return method; + } + final String methodName = method.getName(); + final Class[] parameterTypes = method.getParameterTypes(); + + // Check the implemented interfaces and subinterfaces + method = getAccessibleMethodFromInterfaceNest(cls, methodName, + parameterTypes); + + // Check the superclass chain + if (method == null) { + method = getAccessibleMethodFromSuperclass(cls, methodName, + parameterTypes); + } + return method; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) by scanning through the superclasses. If no such method + * can be found, return {@code null}.

+ * + * @param cls Class to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromSuperclass(final Class cls, + final String methodName, final Class... parameterTypes) { + Class parentClass = cls.getSuperclass(); + while (parentClass != null) { + if (Modifier.isPublic(parentClass.getModifiers())) { + try { + return parentClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException e) { + return null; + } + } + parentClass = parentClass.getSuperclass(); + } + return null; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such method + * can be found, return {@code null}.

+ * + *

There isn't any good reason why this method must be {@code private}. + * It is because there doesn't seem any reason why other classes should + * call this rather than the higher level methods.

+ * + * @param cls Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromInterfaceNest(Class cls, + final String methodName, final Class... parameterTypes) { + // Search up the superclass chain + for (; cls != null; cls = cls.getSuperclass()) { + + // Check the implemented interfaces of the parent class + final Class[] interfaces = cls.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + return interfaces[i].getDeclaredMethod(methodName, + parameterTypes); + } catch (final NoSuchMethodException e) { // NOPMD + /* + * Swallow, if no method is found after the loop then this + * method returns null. + */ + } + // Recursively check our parent interfaces + final Method method = getAccessibleMethodFromInterfaceNest(interfaces[i], + methodName, parameterTypes); + if (method != null) { + return method; + } + } + } + return null; + } + + /** + *

Finds an accessible method that matches the given name and has compatible parameters. + * Compatible parameters mean that every method parameter is assignable from + * the given parameters. + * In other words, it finds a method with the given name + * that will take the parameters given.

+ * + *

This method is used by + * {@link + * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + *

This method can match primitive parameter by passing in wrapper classes. + * For example, a {@code Boolean} will match a primitive {@code boolean} + * parameter. + *

+ * + * @param cls find method in this class + * @param methodName find method with this name + * @param parameterTypes find method with most compatible parameters + * @return The accessible method + */ + public static Method getMatchingAccessibleMethod(final Class cls, + final String methodName, final Class... parameterTypes) { + try { + final Method method = cls.getMethod(methodName, parameterTypes); + MemberUtils.setAccessibleWorkaround(method); + return method; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception + } + // search through all methods + Method bestMatch = null; + final Method[] methods = cls.getMethods(); + for (final Method method : methods) { + // compare name and parameters + if (method.getName().equals(methodName) && + MemberUtils.isMatchingMethod(method, parameterTypes)) { + // get accessible version of method + final Method accessibleMethod = getAccessibleMethod(method); + if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit( + accessibleMethod, + bestMatch, + parameterTypes) < 0)) { + bestMatch = accessibleMethod; + } + } + } + if (bestMatch != null) { + MemberUtils.setAccessibleWorkaround(bestMatch); + } + return bestMatch; + } + + /** + *

Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

+ * @param cls The class that will be subjected to the method search + * @param methodName The method that we wish to call + * @param parameterTypes Argument class types + * @return The method + * + * @since 3.5 + */ + public static Method getMatchingMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + Validate.notNull(cls, "Null class not allowed."); + Validate.notEmpty(methodName, "Null or blank methodName not allowed."); + + // Address methods in superclasses + Method[] methodArray = cls.getDeclaredMethods(); + List> superclassList = ClassUtils.getAllSuperclasses(cls); + for (Class klass : superclassList) { + methodArray = ArrayUtils.addAll(methodArray, klass.getDeclaredMethods()); + } + + Method inexactMatch = null; + for (Method method : methodArray) { + if (methodName.equals(method.getName()) && + ArrayUtils.isEquals(parameterTypes, method.getParameterTypes())) { + return method; + } else if (methodName.equals(method.getName()) && + ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { + if (inexactMatch == null) { + inexactMatch = method; + } else if (distance(parameterTypes, method.getParameterTypes()) + < distance(parameterTypes, inexactMatch.getParameterTypes())) { + inexactMatch = method; + } + } + + } + return inexactMatch; + } + + /** + *

Returns the aggregate number of inheritance hops between assignable argument class types. Returns -1 + * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.

+ * @param classArray + * @param toClassArray + * @return the aggregate number of inheritance hops between assignable argument class types. + */ + private static int distance(Class[] classArray, Class[] toClassArray) { + int answer = 0; + + if (!ClassUtils.isAssignable(classArray, toClassArray, true)) { + return -1; + } + for (int offset = 0; offset < classArray.length; offset++) { + // Note InheritanceUtils.distance() uses different scoring system. + if (classArray[offset].equals(toClassArray[offset])) { + continue; + } else if (ClassUtils.isAssignable(classArray[offset], toClassArray[offset], true) + && !ClassUtils.isAssignable(classArray[offset], toClassArray[offset], false)) { + answer++; + } else { + answer = answer + 2; + } + } + + return answer; + } + + /** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * @param method lowest to consider + * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException if the specified method is {@code null} + * @since 3.2 + */ + public static Set getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { + Validate.notNull(method); + final Set result = new LinkedHashSet(); + result.add(method); + + final Class[] parameterTypes = method.getParameterTypes(); + + final Class declaringClass = method.getDeclaringClass(); + + final Iterator> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); + //skip the declaring class :P + hierarchy.next(); + hierarchyTraversal: while (hierarchy.hasNext()) { + final Class c = hierarchy.next(); + final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); + if (m == null) { + continue; + } + if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { + // matches without generics + result.add(m); + continue; + } + // necessary to get arguments every time in the case that we are including interfaces + final Map, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); + for (int i = 0; i < parameterTypes.length; i++) { + final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); + final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); + if (!TypeUtils.equals(childType, parentType)) { + continue hierarchyTraversal; + } + } + result.add(m); + } + return result; + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched + * @return an array of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Method[] getMethodsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls); + return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]); + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a method to be matched + * @return a list of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getMethodsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final Method[] allMethods = cls.getMethods(); + final List annotatedMethods = new ArrayList(); + for (final Method method : allMethods) { + if (method.getAnnotation(annotationCls) != null) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + +} diff --git a/Java/commons-lang-MethodUtils_383/metadata.json b/Java/commons-lang-MethodUtils_383/metadata.json new file mode 100644 index 000000000..514753ad1 --- /dev/null +++ b/Java/commons-lang-MethodUtils_383/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MethodUtils_383", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 407, + "npe_method": "invokeExactStaticMethod", + "deref_field": "method", + "npe_class": "MethodUtils", + "repo": "commons-lang", + "bug_id": "MethodUtils_383" + } +} diff --git a/Java/commons-lang-MethodUtils_383/npe.json b/Java/commons-lang-MethodUtils_383/npe.json new file mode 100644 index 000000000..9a2ca8185 --- /dev/null +++ b/Java/commons-lang-MethodUtils_383/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 407, + "npe_method": "invokeExactStaticMethod", + "deref_field": "method", + "npe_class": "MethodUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-MethodUtils_452/Dockerfile b/Java/commons-lang-MethodUtils_452/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MethodUtils_452/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MethodUtils_452/buggy.java b/Java/commons-lang-MethodUtils_452/buggy.java new file mode 100644 index 000000000..ef1b5d05b --- /dev/null +++ b/Java/commons-lang-MethodUtils_452/buggy.java @@ -0,0 +1,894 @@ +/* + * 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.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.Validate; + +/** + *

Utility reflection methods focused on {@link Method}s, originally from Commons BeanUtils. + * Differences from the BeanUtils version may be noted, especially where similar functionality + * already existed within Lang. + *

+ * + *

Known Limitations

+ *

Accessing Public Methods In A Default Access Superclass

+ *

There is an issue when invoking {@code public} methods contained in a default access superclass on JREs prior to 1.4. + * Reflection locates these methods fine and correctly assigns them as {@code public}. + * However, an {@link IllegalAccessException} is thrown if the method is invoked.

+ * + *

{@link MethodUtils} contains a workaround for this situation. + * It will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this method. + * If this call succeeds, then the method can be invoked as normal. + * This call will only succeed when the application has sufficient security privileges. + * If this call fails then the method may fail.

+ * + * @since 2.5 + */ +public class MethodUtils { + + /** + *

{@link MethodUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

+ * + *

This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

+ */ + public MethodUtils() { + super(); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.4 + */ + public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, forceAccess, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + args = ArrayUtils.nullToEmpty(args); + + final String messagePrefix; + Method method = null; + boolean isOriginallyAccessible = false; + Object result = null; + + try { + if (forceAccess) { + messagePrefix = "No such method: "; + method = getMatchingMethod(object.getClass(), + methodName, parameterTypes); + if (method != null) { + isOriginallyAccessible = method.isAccessible(); + if (!isOriginallyAccessible) { + method.setAccessible(true); + } + } + } else { + messagePrefix = "No such accessible method: "; + method = getMatchingAccessibleMethod(object.getClass(), + methodName, parameterTypes); + } + + if (method == null) { + throw new NoSuchMethodException(messagePrefix + + methodName + "() on object: " + + object.getClass().getName()); + } + args = toVarArgs(method, args); + + result = method.invoke(object, args); + } + finally { + if (method != null && forceAccess && method.isAccessible() != isOriginallyAccessible) { + method.setAccessible(isOriginallyAccessible); + } + } + + return result; + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + return invokeMethod(object, false, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + * + * @since 3.4 + */ + public static Object invokeExactMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a method with no parameters.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(object.getClass(), methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on object: " + + object.getClass().getName()); + } + return method.invoke(object, args); + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(cls, methodName, parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + return method.invoke(null, args); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeStaticMethod(Class, String, Object[], Class[])}. + *

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ +/** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + * @param cls + * invoke static method on this class + * @param methodName + * get method with this name + * @param args + * use these arguments - treat {@code null} as empty array + * @param parameterTypes + * match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * @throws NoSuchMethodException + * if there is no such accessible method + * @throws InvocationTargetException + * wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException + * if the requested method is not accessible + * via reflection + */ +public static java.lang.Object invokeStaticMethod(final java.lang.Class cls, final java.lang.String methodName, java.lang.Object[] args, java.lang.Class[] parameterTypes) throws java.lang.NoSuchMethodException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException { + args = org.apache.commons.lang3.ArrayUtils.nullToEmpty(args); + parameterTypes = org.apache.commons.lang3.ArrayUtils.nullToEmpty(parameterTypes); + final java.lang.reflect.Method method = org.apache.commons.lang3.reflect.MethodUtils.getMatchingAccessibleMethod(cls, methodName, parameterTypes); + { + args = org.apache.commons.lang3.reflect.MethodUtils.toVarArgs(/* NPEX_NULL_EXP */ + method, args); + return method.invoke(null, args); + } +} + + private static Object[] toVarArgs(Method method, Object[] args) { + if (method.isVarArgs()) { + Class[] methodParameterTypes = method.getParameterTypes(); + args = getVarArgs(args, methodParameterTypes); + } + return args; + } + + /** + *

Given an arguments array passed to a varargs method, return an array of arguments in the canonical form, + * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type. + *

+ * + * @param args the array of arguments passed to the varags method + * @param methodParameterTypes the declared array of method parameter types + * @return an array of the variadic arguments passed to the method + * @since 3.5 + */ + static Object[] getVarArgs(Object[] args, Class[] methodParameterTypes) { + if (args.length == methodParameterTypes.length + && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) { + // The args array is already in the canonical form for the method. + return args; + } + + // Construct a new array matching the method's declared parameter types. + Object[] newArgs = new Object[methodParameterTypes.length]; + + // Copy the normal (non-varargs) parameters + System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1); + + // Construct a new array for the variadic parameters + Class varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + int varArgLength = args.length - methodParameterTypes.length + 1; + + Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength); + // Copy the variadic arguments into the varargs array. + System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength); + + if(varArgComponentType.isPrimitive()) { + // unbox from wrapper type to primitive type + varArgsArray = ArrayUtils.toPrimitive(varArgsArray); + } + + // Store the varargs array in the last position of the array to return + newArgs[methodParameterTypes.length - 1] = varArgsArray; + + // Return the canonical varargs array. + return newArgs; + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) with given name and parameters. If no such method + * can be found, return {@code null}. + * This is just a convenience wrapper for + * {@link #getAccessibleMethod(Method)}.

+ * + * @param cls get method from this class + * @param methodName get method with this name + * @param parameterTypes with these parameters types + * @return The accessible method + */ + public static Method getAccessibleMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + try { + return getAccessibleMethod(cls.getMethod(methodName, + parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return {@code null}.

+ * + * @param method The method that we wish to call + * @return The accessible method + */ + public static Method getAccessibleMethod(Method method) { + if (!MemberUtils.isAccessible(method)) { + return null; + } + // If the declaring class is public, we are done + final Class cls = method.getDeclaringClass(); + if (Modifier.isPublic(cls.getModifiers())) { + return method; + } + final String methodName = method.getName(); + final Class[] parameterTypes = method.getParameterTypes(); + + // Check the implemented interfaces and subinterfaces + method = getAccessibleMethodFromInterfaceNest(cls, methodName, + parameterTypes); + + // Check the superclass chain + if (method == null) { + method = getAccessibleMethodFromSuperclass(cls, methodName, + parameterTypes); + } + return method; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) by scanning through the superclasses. If no such method + * can be found, return {@code null}.

+ * + * @param cls Class to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromSuperclass(final Class cls, + final String methodName, final Class... parameterTypes) { + Class parentClass = cls.getSuperclass(); + while (parentClass != null) { + if (Modifier.isPublic(parentClass.getModifiers())) { + try { + return parentClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException e) { + return null; + } + } + parentClass = parentClass.getSuperclass(); + } + return null; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such method + * can be found, return {@code null}.

+ * + *

There isn't any good reason why this method must be {@code private}. + * It is because there doesn't seem any reason why other classes should + * call this rather than the higher level methods.

+ * + * @param cls Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromInterfaceNest(Class cls, + final String methodName, final Class... parameterTypes) { + // Search up the superclass chain + for (; cls != null; cls = cls.getSuperclass()) { + + // Check the implemented interfaces of the parent class + final Class[] interfaces = cls.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + return interfaces[i].getDeclaredMethod(methodName, + parameterTypes); + } catch (final NoSuchMethodException e) { // NOPMD + /* + * Swallow, if no method is found after the loop then this + * method returns null. + */ + } + // Recursively check our parent interfaces + final Method method = getAccessibleMethodFromInterfaceNest(interfaces[i], + methodName, parameterTypes); + if (method != null) { + return method; + } + } + } + return null; + } + + /** + *

Finds an accessible method that matches the given name and has compatible parameters. + * Compatible parameters mean that every method parameter is assignable from + * the given parameters. + * In other words, it finds a method with the given name + * that will take the parameters given.

+ * + *

This method is used by + * {@link + * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + *

This method can match primitive parameter by passing in wrapper classes. + * For example, a {@code Boolean} will match a primitive {@code boolean} + * parameter. + *

+ * + * @param cls find method in this class + * @param methodName find method with this name + * @param parameterTypes find method with most compatible parameters + * @return The accessible method + */ + public static Method getMatchingAccessibleMethod(final Class cls, + final String methodName, final Class... parameterTypes) { + try { + final Method method = cls.getMethod(methodName, parameterTypes); + MemberUtils.setAccessibleWorkaround(method); + return method; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception + } + // search through all methods + Method bestMatch = null; + final Method[] methods = cls.getMethods(); + for (final Method method : methods) { + // compare name and parameters + if (method.getName().equals(methodName) && + MemberUtils.isMatchingMethod(method, parameterTypes)) { + // get accessible version of method + final Method accessibleMethod = getAccessibleMethod(method); + if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit( + accessibleMethod, + bestMatch, + parameterTypes) < 0)) { + bestMatch = accessibleMethod; + } + } + } + if (bestMatch != null) { + MemberUtils.setAccessibleWorkaround(bestMatch); + } + return bestMatch; + } + + /** + *

Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

+ * @param cls The class that will be subjected to the method search + * @param methodName The method that we wish to call + * @param parameterTypes Argument class types + * @return The method + * + * @since 3.5 + */ + public static Method getMatchingMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + Validate.notNull(cls, "Null class not allowed."); + Validate.notEmpty(methodName, "Null or blank methodName not allowed."); + + // Address methods in superclasses + Method[] methodArray = cls.getDeclaredMethods(); + List> superclassList = ClassUtils.getAllSuperclasses(cls); + for (Class klass : superclassList) { + methodArray = ArrayUtils.addAll(methodArray, klass.getDeclaredMethods()); + } + + Method inexactMatch = null; + for (Method method : methodArray) { + if (methodName.equals(method.getName()) && + ArrayUtils.isEquals(parameterTypes, method.getParameterTypes())) { + return method; + } else if (methodName.equals(method.getName()) && + ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { + if (inexactMatch == null) { + inexactMatch = method; + } else if (distance(parameterTypes, method.getParameterTypes()) + < distance(parameterTypes, inexactMatch.getParameterTypes())) { + inexactMatch = method; + } + } + + } + return inexactMatch; + } + + /** + *

Returns the aggregate number of inheritance hops between assignable argument class types. Returns -1 + * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.

+ * @param classArray + * @param toClassArray + * @return the aggregate number of inheritance hops between assignable argument class types. + */ + private static int distance(Class[] classArray, Class[] toClassArray) { + int answer = 0; + + if (!ClassUtils.isAssignable(classArray, toClassArray, true)) { + return -1; + } + for (int offset = 0; offset < classArray.length; offset++) { + // Note InheritanceUtils.distance() uses different scoring system. + if (classArray[offset].equals(toClassArray[offset])) { + continue; + } else if (ClassUtils.isAssignable(classArray[offset], toClassArray[offset], true) + && !ClassUtils.isAssignable(classArray[offset], toClassArray[offset], false)) { + answer++; + } else { + answer = answer + 2; + } + } + + return answer; + } + + /** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * @param method lowest to consider + * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException if the specified method is {@code null} + * @since 3.2 + */ + public static Set getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { + Validate.notNull(method); + final Set result = new LinkedHashSet(); + result.add(method); + + final Class[] parameterTypes = method.getParameterTypes(); + + final Class declaringClass = method.getDeclaringClass(); + + final Iterator> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); + //skip the declaring class :P + hierarchy.next(); + hierarchyTraversal: while (hierarchy.hasNext()) { + final Class c = hierarchy.next(); + final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); + if (m == null) { + continue; + } + if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { + // matches without generics + result.add(m); + continue; + } + // necessary to get arguments every time in the case that we are including interfaces + final Map, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); + for (int i = 0; i < parameterTypes.length; i++) { + final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); + final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); + if (!TypeUtils.equals(childType, parentType)) { + continue hierarchyTraversal; + } + } + result.add(m); + } + return result; + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched + * @return an array of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Method[] getMethodsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls); + return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]); + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a method to be matched + * @return a list of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getMethodsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final Method[] allMethods = cls.getMethods(); + final List annotatedMethods = new ArrayList(); + for (final Method method : allMethods) { + if (method.getAnnotation(annotationCls) != null) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + +} diff --git a/Java/commons-lang-MethodUtils_452/metadata.json b/Java/commons-lang-MethodUtils_452/metadata.json new file mode 100644 index 000000000..1c92ab4d1 --- /dev/null +++ b/Java/commons-lang-MethodUtils_452/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MethodUtils_452", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 477, + "npe_method": "invokeStaticMethod", + "deref_field": "method", + "npe_class": "MethodUtils", + "repo": "commons-lang", + "bug_id": "MethodUtils_452" + } +} diff --git a/Java/commons-lang-MethodUtils_452/npe.json b/Java/commons-lang-MethodUtils_452/npe.json new file mode 100644 index 000000000..5a4d17b59 --- /dev/null +++ b/Java/commons-lang-MethodUtils_452/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 477, + "npe_method": "invokeStaticMethod", + "deref_field": "method", + "npe_class": "MethodUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-MethodUtils_747/Dockerfile b/Java/commons-lang-MethodUtils_747/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MethodUtils_747/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MethodUtils_747/buggy.java b/Java/commons-lang-MethodUtils_747/buggy.java new file mode 100644 index 000000000..a46b8890a --- /dev/null +++ b/Java/commons-lang-MethodUtils_747/buggy.java @@ -0,0 +1,879 @@ +/* + * 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.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.Validate; + +/** + *

Utility reflection methods focused on {@link Method}s, originally from Commons BeanUtils. + * Differences from the BeanUtils version may be noted, especially where similar functionality + * already existed within Lang. + *

+ * + *

Known Limitations

+ *

Accessing Public Methods In A Default Access Superclass

+ *

There is an issue when invoking {@code public} methods contained in a default access superclass on JREs prior to 1.4. + * Reflection locates these methods fine and correctly assigns them as {@code public}. + * However, an {@link IllegalAccessException} is thrown if the method is invoked.

+ * + *

{@link MethodUtils} contains a workaround for this situation. + * It will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this method. + * If this call succeeds, then the method can be invoked as normal. + * This call will only succeed when the application has sufficient security privileges. + * If this call fails then the method may fail.

+ * + * @since 2.5 + */ +public class MethodUtils { + + /** + *

{@link MethodUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

+ * + *

This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

+ */ + public MethodUtils() { + super(); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.4 + */ + public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, forceAccess, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + args = ArrayUtils.nullToEmpty(args); + + final String messagePrefix; + Method method = null; + boolean isOriginallyAccessible = false; + Object result = null; + + try { + if (forceAccess) { + messagePrefix = "No such method: "; + method = getMatchingMethod(object.getClass(), + methodName, parameterTypes); + if (method != null) { + isOriginallyAccessible = method.isAccessible(); + if (!isOriginallyAccessible) { + method.setAccessible(true); + } + } + } else { + messagePrefix = "No such accessible method: "; + method = getMatchingAccessibleMethod(object.getClass(), + methodName, parameterTypes); + } + + if (method == null) { + throw new NoSuchMethodException(messagePrefix + + methodName + "() on object: " + + object.getClass().getName()); + } + args = toVarArgs(method, args); + + result = method.invoke(object, args); + } + finally { + if (method != null && forceAccess && method.isAccessible() != isOriginallyAccessible) { + method.setAccessible(isOriginallyAccessible); + } + } + + return result; + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + return invokeMethod(object, false, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + * + * @since 3.4 + */ + public static Object invokeExactMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a method with no parameters.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(object.getClass(), methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on object: " + + object.getClass().getName()); + } + return method.invoke(object, args); + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(cls, methodName, parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + return method.invoke(null, args); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeStaticMethod(Class, String, Object[], Class[])}. + *

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getMatchingAccessibleMethod(cls, methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + args = toVarArgs(method, args); + return method.invoke(null, args); + } + + private static Object[] toVarArgs(Method method, Object[] args) { + if (method.isVarArgs()) { + Class[] methodParameterTypes = method.getParameterTypes(); + args = getVarArgs(args, methodParameterTypes); + } + return args; + } + + /** + *

Given an arguments array passed to a varargs method, return an array of arguments in the canonical form, + * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type. + *

+ * + * @param args the array of arguments passed to the varags method + * @param methodParameterTypes the declared array of method parameter types + * @return an array of the variadic arguments passed to the method + * @since 3.5 + */ + static Object[] getVarArgs(Object[] args, Class[] methodParameterTypes) { + if (args.length == methodParameterTypes.length + && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) { + // The args array is already in the canonical form for the method. + return args; + } + + // Construct a new array matching the method's declared parameter types. + Object[] newArgs = new Object[methodParameterTypes.length]; + + // Copy the normal (non-varargs) parameters + System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1); + + // Construct a new array for the variadic parameters + Class varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + int varArgLength = args.length - methodParameterTypes.length + 1; + + Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength); + // Copy the variadic arguments into the varargs array. + System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength); + + if(varArgComponentType.isPrimitive()) { + // unbox from wrapper type to primitive type + varArgsArray = ArrayUtils.toPrimitive(varArgsArray); + } + + // Store the varargs array in the last position of the array to return + newArgs[methodParameterTypes.length - 1] = varArgsArray; + + // Return the canonical varargs array. + return newArgs; + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) with given name and parameters. If no such method + * can be found, return {@code null}. + * This is just a convenience wrapper for + * {@link #getAccessibleMethod(Method)}.

+ * + * @param cls get method from this class + * @param methodName get method with this name + * @param parameterTypes with these parameters types + * @return The accessible method + */ + public static Method getAccessibleMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + try { + return getAccessibleMethod(cls.getMethod(methodName, + parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return {@code null}.

+ * + * @param method The method that we wish to call + * @return The accessible method + */ + public static Method getAccessibleMethod(Method method) { + if (!MemberUtils.isAccessible(method)) { + return null; + } + // If the declaring class is public, we are done + final Class cls = method.getDeclaringClass(); + if (Modifier.isPublic(cls.getModifiers())) { + return method; + } + final String methodName = method.getName(); + final Class[] parameterTypes = method.getParameterTypes(); + + // Check the implemented interfaces and subinterfaces + method = getAccessibleMethodFromInterfaceNest(cls, methodName, + parameterTypes); + + // Check the superclass chain + if (method == null) { + method = getAccessibleMethodFromSuperclass(cls, methodName, + parameterTypes); + } + return method; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) by scanning through the superclasses. If no such method + * can be found, return {@code null}.

+ * + * @param cls Class to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromSuperclass(final Class cls, + final String methodName, final Class... parameterTypes) { + Class parentClass = cls.getSuperclass(); + while (parentClass != null) { + if (Modifier.isPublic(parentClass.getModifiers())) { + try { + return parentClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException e) { + return null; + } + } + parentClass = parentClass.getSuperclass(); + } + return null; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such method + * can be found, return {@code null}.

+ * + *

There isn't any good reason why this method must be {@code private}. + * It is because there doesn't seem any reason why other classes should + * call this rather than the higher level methods.

+ * + * @param cls Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromInterfaceNest(Class cls, + final String methodName, final Class... parameterTypes) { + // Search up the superclass chain + for (; cls != null; cls = cls.getSuperclass()) { + + // Check the implemented interfaces of the parent class + final Class[] interfaces = cls.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + return interfaces[i].getDeclaredMethod(methodName, + parameterTypes); + } catch (final NoSuchMethodException e) { // NOPMD + /* + * Swallow, if no method is found after the loop then this + * method returns null. + */ + } + // Recursively check our parent interfaces + final Method method = getAccessibleMethodFromInterfaceNest(interfaces[i], + methodName, parameterTypes); + if (method != null) { + return method; + } + } + } + return null; + } + + /** + *

Finds an accessible method that matches the given name and has compatible parameters. + * Compatible parameters mean that every method parameter is assignable from + * the given parameters. + * In other words, it finds a method with the given name + * that will take the parameters given.

+ * + *

This method is used by + * {@link + * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + *

This method can match primitive parameter by passing in wrapper classes. + * For example, a {@code Boolean} will match a primitive {@code boolean} + * parameter. + *

+ * + * @param cls find method in this class + * @param methodName find method with this name + * @param parameterTypes find method with most compatible parameters + * @return The accessible method + */ + public static Method getMatchingAccessibleMethod(final Class cls, + final String methodName, final Class... parameterTypes) { + try { + final Method method = cls.getMethod(methodName, parameterTypes); + MemberUtils.setAccessibleWorkaround(method); + return method; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception + } + // search through all methods + Method bestMatch = null; + final Method[] methods = cls.getMethods(); + for (final Method method : methods) { + // compare name and parameters + if (method.getName().equals(methodName) && + MemberUtils.isMatchingMethod(method, parameterTypes)) { + // get accessible version of method + final Method accessibleMethod = getAccessibleMethod(method); + if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit( + accessibleMethod, + bestMatch, + parameterTypes) < 0)) { + bestMatch = accessibleMethod; + } + } + } + if (bestMatch != null) { + MemberUtils.setAccessibleWorkaround(bestMatch); + } + return bestMatch; + } + + /** + *

Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

+ * @param cls The class that will be subjected to the method search + * @param methodName The method that we wish to call + * @param parameterTypes Argument class types + * @return The method + * + * @since 3.5 + */ +/** + *

Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

+ * + * @param cls + * The class that will be subjected to the method search + * @param methodName + * The method that we wish to call + * @param parameterTypes + * Argument class types + * @return The method + * @since 3.5 + */ +public static java.lang.reflect.Method getMatchingMethod(final java.lang.Class cls, final java.lang.String methodName, final java.lang.Class... parameterTypes) { + org.apache.commons.lang3.Validate.notNull(cls, "Null class not allowed."); + org.apache.commons.lang3.Validate.notEmpty(methodName, "Null or blank methodName not allowed."); + // Address methods in superclasses + java.lang.reflect.Method[] methodArray = cls.getDeclaredMethods(); + java.util.List> superclassList = org.apache.commons.lang3.ClassUtils.getAllSuperclasses(cls); + for (java.lang.Class klass : superclassList) { + methodArray = org.apache.commons.lang3.ArrayUtils.addAll(methodArray, klass.getDeclaredMethods()); + } + java.lang.reflect.Method inexactMatch = null; + for (java.lang.reflect.Method method : methodArray) { + if (methodName.equals(method.getName()) && org.apache.commons.lang3.ArrayUtils.isEquals(parameterTypes, method.getParameterTypes())) { + return method; + } else if (methodName.equals(method.getName()) && org.apache.commons.lang3.ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { + { + if (org.apache.commons.lang3.reflect.MethodUtils.distance(parameterTypes, method.getParameterTypes()) < org.apache.commons.lang3.reflect.MethodUtils.distance(parameterTypes, /* NPEX_NULL_EXP */ + inexactMatch.getParameterTypes())) { + inexactMatch = method; + } + } + } + } + return inexactMatch; +} + + /** + *

Returns the aggregate number of inheritance hops between assignable argument class types. Returns -1 + * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.

+ * @param classArray + * @param toClassArray + * @return the aggregate number of inheritance hops between assignable argument class types. + */ + private static int distance(Class[] classArray, Class[] toClassArray) { + int answer = 0; + + if (!ClassUtils.isAssignable(classArray, toClassArray, true)) { + return -1; + } + for (int offset = 0; offset < classArray.length; offset++) { + // Note InheritanceUtils.distance() uses different scoring system. + if (classArray[offset].equals(toClassArray[offset])) { + continue; + } else if (ClassUtils.isAssignable(classArray[offset], toClassArray[offset], true) + && !ClassUtils.isAssignable(classArray[offset], toClassArray[offset], false)) { + answer++; + } else { + answer = answer + 2; + } + } + + return answer; + } + + /** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * @param method lowest to consider + * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException if the specified method is {@code null} + * @since 3.2 + */ + public static Set getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { + Validate.notNull(method); + final Set result = new LinkedHashSet(); + result.add(method); + + final Class[] parameterTypes = method.getParameterTypes(); + + final Class declaringClass = method.getDeclaringClass(); + + final Iterator> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); + //skip the declaring class :P + hierarchy.next(); + hierarchyTraversal: while (hierarchy.hasNext()) { + final Class c = hierarchy.next(); + final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); + if (m == null) { + continue; + } + if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { + // matches without generics + result.add(m); + continue; + } + // necessary to get arguments every time in the case that we are including interfaces + final Map, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); + for (int i = 0; i < parameterTypes.length; i++) { + final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); + final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); + if (!TypeUtils.equals(childType, parentType)) { + continue hierarchyTraversal; + } + } + result.add(m); + } + return result; + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched + * @return an array of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Method[] getMethodsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls); + return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]); + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a method to be matched + * @return a list of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getMethodsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final Method[] allMethods = cls.getMethods(); + final List annotatedMethods = new ArrayList(); + for (final Method method : allMethods) { + if (method.getAnnotation(annotationCls) != null) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + +} diff --git a/Java/commons-lang-MethodUtils_747/metadata.json b/Java/commons-lang-MethodUtils_747/metadata.json new file mode 100644 index 000000000..0763eb617 --- /dev/null +++ b/Java/commons-lang-MethodUtils_747/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MethodUtils_747", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 757, + "npe_method": "getMatchingMethod", + "deref_field": "inexactMatch", + "npe_class": "MethodUtils", + "repo": "commons-lang", + "bug_id": "MethodUtils_747" + } +} diff --git a/Java/commons-lang-MethodUtils_747/npe.json b/Java/commons-lang-MethodUtils_747/npe.json new file mode 100644 index 000000000..7646c6d3e --- /dev/null +++ b/Java/commons-lang-MethodUtils_747/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 757, + "npe_method": "getMatchingMethod", + "deref_field": "inexactMatch", + "npe_class": "MethodUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-MethodUtils_810/Dockerfile b/Java/commons-lang-MethodUtils_810/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MethodUtils_810/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MethodUtils_810/buggy.java b/Java/commons-lang-MethodUtils_810/buggy.java new file mode 100644 index 000000000..9e34a388f --- /dev/null +++ b/Java/commons-lang-MethodUtils_810/buggy.java @@ -0,0 +1,881 @@ +/* + * 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.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.Validate; + +/** + *

Utility reflection methods focused on {@link Method}s, originally from Commons BeanUtils. + * Differences from the BeanUtils version may be noted, especially where similar functionality + * already existed within Lang. + *

+ * + *

Known Limitations

+ *

Accessing Public Methods In A Default Access Superclass

+ *

There is an issue when invoking {@code public} methods contained in a default access superclass on JREs prior to 1.4. + * Reflection locates these methods fine and correctly assigns them as {@code public}. + * However, an {@link IllegalAccessException} is thrown if the method is invoked.

+ * + *

{@link MethodUtils} contains a workaround for this situation. + * It will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this method. + * If this call succeeds, then the method can be invoked as normal. + * This call will only succeed when the application has sufficient security privileges. + * If this call fails then the method may fail.

+ * + * @since 2.5 + */ +public class MethodUtils { + + /** + *

{@link MethodUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

+ * + *

This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

+ */ + public MethodUtils() { + super(); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.4 + */ + public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method without parameters.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, forceAccess, methodName, args, parameterTypes); + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + args = ArrayUtils.nullToEmpty(args); + + final String messagePrefix; + Method method = null; + boolean isOriginallyAccessible = false; + Object result = null; + + try { + if (forceAccess) { + messagePrefix = "No such method: "; + method = getMatchingMethod(object.getClass(), + methodName, parameterTypes); + if (method != null) { + isOriginallyAccessible = method.isAccessible(); + if (!isOriginallyAccessible) { + method.setAccessible(true); + } + } + } else { + messagePrefix = "No such accessible method: "; + method = getMatchingAccessibleMethod(object.getClass(), + methodName, parameterTypes); + } + + if (method == null) { + throw new NoSuchMethodException(messagePrefix + + methodName + "() on object: " + + object.getClass().getName()); + } + args = toVarArgs(method, args); + + result = method.invoke(object, args); + } + finally { + if (method != null && forceAccess && method.isAccessible() != isOriginallyAccessible) { + method.setAccessible(isOriginallyAccessible); + } + } + + return result; + } + + /** + *

Invokes a named method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + return invokeMethod(object, false, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + * + * @since 3.4 + */ + public static Object invokeExactMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

Invokes a method with no parameters.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactMethod(object, methodName, args, parameterTypes); + } + + /** + *

Invokes a method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

+ * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(object.getClass(), methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on object: " + + object.getClass().getName()); + } + return method.invoke(object, args); + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(cls, methodName, parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + return method.invoke(null, args); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + *

This is a convenient wrapper for + * {@link #invokeStaticMethod(Class, String, Object[], Class[])}. + *

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Invokes a named {@code static} method whose parameter type matches the object type.

+ * + *

This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

+ * + *

This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

+ * + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getMatchingAccessibleMethod(cls, methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + args = toVarArgs(method, args); + return method.invoke(null, args); + } + + private static Object[] toVarArgs(Method method, Object[] args) { + if (method.isVarArgs()) { + Class[] methodParameterTypes = method.getParameterTypes(); + args = getVarArgs(args, methodParameterTypes); + } + return args; + } + + /** + *

Given an arguments array passed to a varargs method, return an array of arguments in the canonical form, + * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type. + *

+ * + * @param args the array of arguments passed to the varags method + * @param methodParameterTypes the declared array of method parameter types + * @return an array of the variadic arguments passed to the method + * @since 3.5 + */ + static Object[] getVarArgs(Object[] args, Class[] methodParameterTypes) { + if (args.length == methodParameterTypes.length + && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) { + // The args array is already in the canonical form for the method. + return args; + } + + // Construct a new array matching the method's declared parameter types. + Object[] newArgs = new Object[methodParameterTypes.length]; + + // Copy the normal (non-varargs) parameters + System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1); + + // Construct a new array for the variadic parameters + Class varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + int varArgLength = args.length - methodParameterTypes.length + 1; + + Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength); + // Copy the variadic arguments into the varargs array. + System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength); + + if(varArgComponentType.isPrimitive()) { + // unbox from wrapper type to primitive type + varArgsArray = ArrayUtils.toPrimitive(varArgsArray); + } + + // Store the varargs array in the last position of the array to return + newArgs[methodParameterTypes.length - 1] = varArgsArray; + + // Return the canonical varargs array. + return newArgs; + } + + /** + *

Invokes a {@code static} method whose parameter types match exactly the object + * types.

+ * + *

This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

+ * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) with given name and parameters. If no such method + * can be found, return {@code null}. + * This is just a convenience wrapper for + * {@link #getAccessibleMethod(Method)}.

+ * + * @param cls get method from this class + * @param methodName get method with this name + * @param parameterTypes with these parameters types + * @return The accessible method + */ + public static Method getAccessibleMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + try { + return getAccessibleMethod(cls.getMethod(methodName, + parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return {@code null}.

+ * + * @param method The method that we wish to call + * @return The accessible method + */ + public static Method getAccessibleMethod(Method method) { + if (!MemberUtils.isAccessible(method)) { + return null; + } + // If the declaring class is public, we are done + final Class cls = method.getDeclaringClass(); + if (Modifier.isPublic(cls.getModifiers())) { + return method; + } + final String methodName = method.getName(); + final Class[] parameterTypes = method.getParameterTypes(); + + // Check the implemented interfaces and subinterfaces + method = getAccessibleMethodFromInterfaceNest(cls, methodName, + parameterTypes); + + // Check the superclass chain + if (method == null) { + method = getAccessibleMethodFromSuperclass(cls, methodName, + parameterTypes); + } + return method; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) by scanning through the superclasses. If no such method + * can be found, return {@code null}.

+ * + * @param cls Class to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromSuperclass(final Class cls, + final String methodName, final Class... parameterTypes) { + Class parentClass = cls.getSuperclass(); + while (parentClass != null) { + if (Modifier.isPublic(parentClass.getModifiers())) { + try { + return parentClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException e) { + return null; + } + } + parentClass = parentClass.getSuperclass(); + } + return null; + } + + /** + *

Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such method + * can be found, return {@code null}.

+ * + *

There isn't any good reason why this method must be {@code private}. + * It is because there doesn't seem any reason why other classes should + * call this rather than the higher level methods.

+ * + * @param cls Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromInterfaceNest(Class cls, + final String methodName, final Class... parameterTypes) { + // Search up the superclass chain + for (; cls != null; cls = cls.getSuperclass()) { + + // Check the implemented interfaces of the parent class + final Class[] interfaces = cls.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + return interfaces[i].getDeclaredMethod(methodName, + parameterTypes); + } catch (final NoSuchMethodException e) { // NOPMD + /* + * Swallow, if no method is found after the loop then this + * method returns null. + */ + } + // Recursively check our parent interfaces + final Method method = getAccessibleMethodFromInterfaceNest(interfaces[i], + methodName, parameterTypes); + if (method != null) { + return method; + } + } + } + return null; + } + + /** + *

Finds an accessible method that matches the given name and has compatible parameters. + * Compatible parameters mean that every method parameter is assignable from + * the given parameters. + * In other words, it finds a method with the given name + * that will take the parameters given.

+ * + *

This method is used by + * {@link + * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. + *

+ * + *

This method can match primitive parameter by passing in wrapper classes. + * For example, a {@code Boolean} will match a primitive {@code boolean} + * parameter. + *

+ * + * @param cls find method in this class + * @param methodName find method with this name + * @param parameterTypes find method with most compatible parameters + * @return The accessible method + */ + public static Method getMatchingAccessibleMethod(final Class cls, + final String methodName, final Class... parameterTypes) { + try { + final Method method = cls.getMethod(methodName, parameterTypes); + MemberUtils.setAccessibleWorkaround(method); + return method; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception + } + // search through all methods + Method bestMatch = null; + final Method[] methods = cls.getMethods(); + for (final Method method : methods) { + // compare name and parameters + if (method.getName().equals(methodName) && + MemberUtils.isMatchingMethod(method, parameterTypes)) { + // get accessible version of method + final Method accessibleMethod = getAccessibleMethod(method); + if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit( + accessibleMethod, + bestMatch, + parameterTypes) < 0)) { + bestMatch = accessibleMethod; + } + } + } + if (bestMatch != null) { + MemberUtils.setAccessibleWorkaround(bestMatch); + } + return bestMatch; + } + + /** + *

Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

+ * @param cls The class that will be subjected to the method search + * @param methodName The method that we wish to call + * @param parameterTypes Argument class types + * @return The method + * + * @since 3.5 + */ + public static Method getMatchingMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + Validate.notNull(cls, "Null class not allowed."); + Validate.notEmpty(methodName, "Null or blank methodName not allowed."); + + // Address methods in superclasses + Method[] methodArray = cls.getDeclaredMethods(); + List> superclassList = ClassUtils.getAllSuperclasses(cls); + for (Class klass : superclassList) { + methodArray = ArrayUtils.addAll(methodArray, klass.getDeclaredMethods()); + } + + Method inexactMatch = null; + for (Method method : methodArray) { + if (methodName.equals(method.getName()) && + ArrayUtils.isEquals(parameterTypes, method.getParameterTypes())) { + return method; + } else if (methodName.equals(method.getName()) && + ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { + if (inexactMatch == null) { + inexactMatch = method; + } else if (distance(parameterTypes, method.getParameterTypes()) + < distance(parameterTypes, inexactMatch.getParameterTypes())) { + inexactMatch = method; + } + } + + } + return inexactMatch; + } + + /** + *

Returns the aggregate number of inheritance hops between assignable argument class types. Returns -1 + * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.

+ * @param classArray + * @param toClassArray + * @return the aggregate number of inheritance hops between assignable argument class types. + */ + private static int distance(Class[] classArray, Class[] toClassArray) { + int answer = 0; + + if (!ClassUtils.isAssignable(classArray, toClassArray, true)) { + return -1; + } + for (int offset = 0; offset < classArray.length; offset++) { + // Note InheritanceUtils.distance() uses different scoring system. + if (classArray[offset].equals(toClassArray[offset])) { + continue; + } else if (ClassUtils.isAssignable(classArray[offset], toClassArray[offset], true) + && !ClassUtils.isAssignable(classArray[offset], toClassArray[offset], false)) { + answer++; + } else { + answer = answer + 2; + } + } + + return answer; + } + + /** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * @param method lowest to consider + * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException if the specified method is {@code null} + * @since 3.2 + */ +/** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * + * @param method + * lowest to consider + * @param interfacesBehavior + * whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException + * if the specified method is {@code null} + * @since 3.2 + */ +public static java.util.Set getOverrideHierarchy(final java.lang.reflect.Method method, final org.apache.commons.lang3.ClassUtils.Interfaces interfacesBehavior) { + org.apache.commons.lang3.Validate.notNull(method); + final java.util.Set result = new java.util.LinkedHashSet(); + result.add(method); + final java.lang.Class[] parameterTypes = method.getParameterTypes(); + final java.lang.Class declaringClass = method.getDeclaringClass(); + final java.util.Iterator> hierarchy = org.apache.commons.lang3.ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); + // skip the declaring class :P + hierarchy.next(); + hierarchyTraversal : while (hierarchy.hasNext()) { + final java.lang.Class c = hierarchy.next(); + final java.lang.reflect.Method m = org.apache.commons.lang3.reflect.MethodUtils.getMatchingAccessibleMethod(c, method.getName(), parameterTypes); + { + if (java.util.Arrays.equals(/* NPEX_NULL_EXP */ + m.getParameterTypes(), parameterTypes)) { + // matches without generics + result.add(m); + continue; + } + // necessary to get arguments every time in the case that we are including interfaces + final java.util.Map, java.lang.reflect.Type> typeArguments = org.apache.commons.lang3.reflect.TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); + for (int i = 0; i < parameterTypes.length; i++) { + final java.lang.reflect.Type childType = org.apache.commons.lang3.reflect.TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); + final java.lang.reflect.Type parentType = org.apache.commons.lang3.reflect.TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); + if (!org.apache.commons.lang3.reflect.TypeUtils.equals(childType, parentType)) { + continue hierarchyTraversal; + } + } + result.add(m); + } + } + return result; +} + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched + * @return an array of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Method[] getMethodsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls); + return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]); + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a method to be matched + * @return a list of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getMethodsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final Method[] allMethods = cls.getMethods(); + final List annotatedMethods = new ArrayList(); + for (final Method method : allMethods) { + if (method.getAnnotation(annotationCls) != null) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + +} diff --git a/Java/commons-lang-MethodUtils_810/metadata.json b/Java/commons-lang-MethodUtils_810/metadata.json new file mode 100644 index 000000000..a3b9a18fd --- /dev/null +++ b/Java/commons-lang-MethodUtils_810/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MethodUtils_810", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 821, + "npe_method": "getOverrideHierarchy", + "deref_field": "m", + "npe_class": "MethodUtils", + "repo": "commons-lang", + "bug_id": "MethodUtils_810" + } +} diff --git a/Java/commons-lang-MethodUtils_810/npe.json b/Java/commons-lang-MethodUtils_810/npe.json new file mode 100644 index 000000000..b6d7d238b --- /dev/null +++ b/Java/commons-lang-MethodUtils_810/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java", + "line": 821, + "npe_method": "getOverrideHierarchy", + "deref_field": "m", + "npe_class": "MethodUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-MultiBackgroundInitializer_134/Dockerfile b/Java/commons-lang-MultiBackgroundInitializer_134/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_134/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MultiBackgroundInitializer_134/buggy.java b/Java/commons-lang-MultiBackgroundInitializer_134/buggy.java new file mode 100644 index 000000000..682438531 --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_134/buggy.java @@ -0,0 +1,363 @@ +/* + * 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.commons.lang3.concurrent; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +/** + *

+ * A specialized {@link BackgroundInitializer} implementation that can deal with + * multiple background initialization tasks. + *

+ *

+ * This class has a similar purpose as {@link BackgroundInitializer}. However, + * it is not limited to a single background initialization task. Rather it + * manages an arbitrary number of {@code BackgroundInitializer} objects, + * executes them, and waits until they are completely initialized. This is + * useful for applications that have to perform multiple initialization tasks + * that can run in parallel (i.e. that do not depend on each other). This class + * takes care about the management of an {@code ExecutorService} and shares it + * with the {@code BackgroundInitializer} objects it is responsible for; so the + * using application need not bother with these details. + *

+ *

+ * The typical usage scenario for {@code MultiBackgroundInitializer} is as + * follows: + *

+ *
    + *
  • Create a new instance of the class. Optionally pass in a pre-configured + * {@code ExecutorService}. Alternatively {@code MultiBackgroundInitializer} can + * create a temporary {@code ExecutorService} and delete it after initialization + * is complete.
  • + *
  • Create specialized {@link BackgroundInitializer} objects for the + * initialization tasks to be performed and add them to the {@code + * MultiBackgroundInitializer} using the + * {@link #addInitializer(String, BackgroundInitializer)} method.
  • + *
  • After all initializers have been added, call the {@link #start()} method. + *
  • + *
  • When access to the result objects produced by the {@code + * BackgroundInitializer} objects is needed call the {@link #get()} method. The + * object returned here provides access to all result objects created during + * initialization. It also stores information about exceptions that have + * occurred.
  • + *
+ *

+ * {@code MultiBackgroundInitializer} starts a special controller task that + * starts all {@code BackgroundInitializer} objects added to the instance. + * Before the an initializer is started it is checked whether this initializer + * already has an {@code ExecutorService} set. If this is the case, this {@code + * ExecutorService} is used for running the background task. Otherwise the + * current {@code ExecutorService} of this {@code MultiBackgroundInitializer} is + * shared with the initializer. + *

+ *

+ * The easiest way of using this class is to let it deal with the management of + * an {@code ExecutorService} itself: If no external {@code ExecutorService} is + * provided, the class creates a temporary {@code ExecutorService} (that is + * capable of executing all background tasks in parallel) and destroys it at the + * end of background processing. + *

+ *

+ * Alternatively an external {@code ExecutorService} can be provided - either at + * construction time or later by calling the + * {@link #setExternalExecutor(ExecutorService)} method. In this case all + * background tasks are scheduled at this external {@code ExecutorService}. + * Important note: When using an external {@code + * ExecutorService} be sure that the number of threads managed by the service is + * large enough. Otherwise a deadlock can happen! This is the case in the + * following scenario: {@code MultiBackgroundInitializer} starts a task that + * starts all registered {@code BackgroundInitializer} objects and waits for + * their completion. If for instance a single threaded {@code ExecutorService} + * is used, none of the background tasks can be executed, and the task created + * by {@code MultiBackgroundInitializer} waits forever. + *

+ * + * @since 3.0 + */ +public class MultiBackgroundInitializer + extends + BackgroundInitializer { + /** A map with the child initializers. */ + private final Map> childInitializers = + new HashMap>(); + + /** + * Creates a new instance of {@code MultiBackgroundInitializer}. + */ + public MultiBackgroundInitializer() { + super(); + } + + /** + * Creates a new instance of {@code MultiBackgroundInitializer} and + * initializes it with the given external {@code ExecutorService}. + * + * @param exec the {@code ExecutorService} for executing the background + * tasks + */ + public MultiBackgroundInitializer(final ExecutorService exec) { + super(exec); + } + + /** + * Adds a new {@code BackgroundInitializer} to this object. When this + * {@code MultiBackgroundInitializer} is started, the given initializer will + * be processed. This method must not be called after {@link #start()} has + * been invoked. + * + * @param name the name of the initializer (must not be null) + * @param init the {@code BackgroundInitializer} to add (must not be + * null) + * @throws IllegalArgumentException if a required parameter is missing + * @throws IllegalStateException if {@code start()} has already been called + */ +/** + * Adds a new {@code BackgroundInitializer} to this object. When this + * {@code MultiBackgroundInitializer} is started, the given initializer will + * be processed. This method must not be called after {@link #start()} has + * been invoked. + * + * @param name + * the name of the initializer (must not be null) + * @param init + * the {@code BackgroundInitializer} to add (must not be + * null) + * @throws IllegalArgumentException + * if a required parameter is missing + * @throws IllegalStateException + * if {@code start()} has already been called + */ +public void addInitializer(final java.lang.String name, final org.apache.commons.lang3.concurrent.BackgroundInitializer init) { + { + if (init == null) { + throw new java.lang.IllegalArgumentException("Child initializer must not be null!"); + } + synchronized(this) { + if (isStarted()) { + throw new java.lang.IllegalStateException("addInitializer() must not be called after start()!"); + } + childInitializers.put(/* NPEX_NULL_EXP */ + name, init); + } + } +} + + /** + * Returns the number of tasks needed for executing all child {@code + * BackgroundInitializer} objects in parallel. This implementation sums up + * the required tasks for all child initializers (which is necessary if one + * of the child initializers is itself a {@code MultiBackgroundInitializer} + * ). Then it adds 1 for the control task that waits for the completion of + * the children. + * + * @return the number of tasks required for background processing + */ + @Override + protected int getTaskCount() { + int result = 1; + + for (final BackgroundInitializer bi : childInitializers.values()) { + result += bi.getTaskCount(); + } + + return result; + } + + /** + * Creates the results object. This implementation starts all child {@code + * BackgroundInitializer} objects. Then it collects their results and + * creates a {@code MultiBackgroundInitializerResults} object with this + * data. If a child initializer throws a checked exceptions, it is added to + * the results object. Unchecked exceptions are propagated. + * + * @return the results object + * @throws Exception if an error occurs + */ + @Override + protected MultiBackgroundInitializerResults initialize() throws Exception { + Map> inits; + synchronized (this) { + // create a snapshot to operate on + inits = new HashMap>( + childInitializers); + } + + // start the child initializers + final ExecutorService exec = getActiveExecutor(); + for (final BackgroundInitializer bi : inits.values()) { + if (bi.getExternalExecutor() == null) { + // share the executor service if necessary + bi.setExternalExecutor(exec); + } + bi.start(); + } + + // collect the results + final Map results = new HashMap(); + final Map excepts = new HashMap(); + for (final Map.Entry> e : inits.entrySet()) { + try { + results.put(e.getKey(), e.getValue().get()); + } catch (final ConcurrentException cex) { + excepts.put(e.getKey(), cex); + } + } + + return new MultiBackgroundInitializerResults(inits, results, excepts); + } + + /** + * A data class for storing the results of the background initialization + * performed by {@code MultiBackgroundInitializer}. Objects of this inner + * class are returned by {@link MultiBackgroundInitializer#initialize()}. + * They allow access to all result objects produced by the + * {@link BackgroundInitializer} objects managed by the owning instance. It + * is also possible to retrieve status information about single + * {@link BackgroundInitializer}s, i.e. whether they completed normally or + * caused an exception. + */ + public static class MultiBackgroundInitializerResults { + /** A map with the child initializers. */ + private final Map> initializers; + + /** A map with the result objects. */ + private final Map resultObjects; + + /** A map with the exceptions. */ + private final Map exceptions; + + /** + * Creates a new instance of {@code MultiBackgroundInitializerResults} + * and initializes it with maps for the {@code BackgroundInitializer} + * objects, their result objects and the exceptions thrown by them. + * + * @param inits the {@code BackgroundInitializer} objects + * @param results the result objects + * @param excepts the exceptions + */ + private MultiBackgroundInitializerResults( + final Map> inits, + final Map results, + final Map excepts) { + initializers = inits; + resultObjects = results; + exceptions = excepts; + } + + /** + * Returns the {@code BackgroundInitializer} with the given name. If the + * name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the {@code BackgroundInitializer} with this name + * @throws NoSuchElementException if the name cannot be resolved + */ + public BackgroundInitializer getInitializer(final String name) { + return checkName(name); + } + + /** + * Returns the result object produced by the {@code + * BackgroundInitializer} with the given name. This is the object + * returned by the initializer's {@code initialize()} method. If this + * {@code BackgroundInitializer} caused an exception, null is + * returned. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the result object produced by this {@code + * BackgroundInitializer} + * @throws NoSuchElementException if the name cannot be resolved + */ + public Object getResultObject(final String name) { + checkName(name); + return resultObjects.get(name); + } + + /** + * Returns a flag whether the {@code BackgroundInitializer} with the + * given name caused an exception. + * + * @param name the name of the {@code BackgroundInitializer} + * @return a flag whether this initializer caused an exception + * @throws NoSuchElementException if the name cannot be resolved + */ + public boolean isException(final String name) { + checkName(name); + return exceptions.containsKey(name); + } + + /** + * Returns the {@code ConcurrentException} object that was thrown by the + * {@code BackgroundInitializer} with the given name. If this + * initializer did not throw an exception, the return value is + * null. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the exception thrown by this initializer + * @throws NoSuchElementException if the name cannot be resolved + */ + public ConcurrentException getException(final String name) { + checkName(name); + return exceptions.get(name); + } + + /** + * Returns a set with the names of all {@code BackgroundInitializer} + * objects managed by the {@code MultiBackgroundInitializer}. + * + * @return an (unmodifiable) set with the names of the managed {@code + * BackgroundInitializer} objects + */ + public Set initializerNames() { + return Collections.unmodifiableSet(initializers.keySet()); + } + + /** + * Returns a flag whether the whole initialization was successful. This + * is the case if no child initializer has thrown an exception. + * + * @return a flag whether the initialization was successful + */ + public boolean isSuccessful() { + return exceptions.isEmpty(); + } + + /** + * Checks whether an initializer with the given name exists. If not, + * throws an exception. If it exists, the associated child initializer + * is returned. + * + * @param name the name to check + * @return the initializer with this name + * @throws NoSuchElementException if the name is unknown + */ + private BackgroundInitializer checkName(final String name) { + final BackgroundInitializer init = initializers.get(name); + if (init == null) { + throw new NoSuchElementException( + "No child initializer with name " + name); + } + + return init; + } + } +} diff --git a/Java/commons-lang-MultiBackgroundInitializer_134/metadata.json b/Java/commons-lang-MultiBackgroundInitializer_134/metadata.json new file mode 100644 index 000000000..9ab5a8eba --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_134/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MultiBackgroundInitializer_134", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java", + "line": 159, + "npe_method": "addInitializer", + "deref_field": "name", + "npe_class": "MultiBackgroundInitializer", + "repo": "commons-lang", + "bug_id": "MultiBackgroundInitializer_134" + } +} diff --git a/Java/commons-lang-MultiBackgroundInitializer_134/npe.json b/Java/commons-lang-MultiBackgroundInitializer_134/npe.json new file mode 100644 index 000000000..d79ec6c21 --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_134/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java", + "line": 159, + "npe_method": "addInitializer", + "deref_field": "name", + "npe_class": "MultiBackgroundInitializer" +} \ No newline at end of file diff --git a/Java/commons-lang-MultiBackgroundInitializer_138/Dockerfile b/Java/commons-lang-MultiBackgroundInitializer_138/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_138/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MultiBackgroundInitializer_138/buggy.java b/Java/commons-lang-MultiBackgroundInitializer_138/buggy.java new file mode 100644 index 000000000..6c440f36e --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_138/buggy.java @@ -0,0 +1,363 @@ +/* + * 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.commons.lang3.concurrent; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +/** + *

+ * A specialized {@link BackgroundInitializer} implementation that can deal with + * multiple background initialization tasks. + *

+ *

+ * This class has a similar purpose as {@link BackgroundInitializer}. However, + * it is not limited to a single background initialization task. Rather it + * manages an arbitrary number of {@code BackgroundInitializer} objects, + * executes them, and waits until they are completely initialized. This is + * useful for applications that have to perform multiple initialization tasks + * that can run in parallel (i.e. that do not depend on each other). This class + * takes care about the management of an {@code ExecutorService} and shares it + * with the {@code BackgroundInitializer} objects it is responsible for; so the + * using application need not bother with these details. + *

+ *

+ * The typical usage scenario for {@code MultiBackgroundInitializer} is as + * follows: + *

+ *
    + *
  • Create a new instance of the class. Optionally pass in a pre-configured + * {@code ExecutorService}. Alternatively {@code MultiBackgroundInitializer} can + * create a temporary {@code ExecutorService} and delete it after initialization + * is complete.
  • + *
  • Create specialized {@link BackgroundInitializer} objects for the + * initialization tasks to be performed and add them to the {@code + * MultiBackgroundInitializer} using the + * {@link #addInitializer(String, BackgroundInitializer)} method.
  • + *
  • After all initializers have been added, call the {@link #start()} method. + *
  • + *
  • When access to the result objects produced by the {@code + * BackgroundInitializer} objects is needed call the {@link #get()} method. The + * object returned here provides access to all result objects created during + * initialization. It also stores information about exceptions that have + * occurred.
  • + *
+ *

+ * {@code MultiBackgroundInitializer} starts a special controller task that + * starts all {@code BackgroundInitializer} objects added to the instance. + * Before the an initializer is started it is checked whether this initializer + * already has an {@code ExecutorService} set. If this is the case, this {@code + * ExecutorService} is used for running the background task. Otherwise the + * current {@code ExecutorService} of this {@code MultiBackgroundInitializer} is + * shared with the initializer. + *

+ *

+ * The easiest way of using this class is to let it deal with the management of + * an {@code ExecutorService} itself: If no external {@code ExecutorService} is + * provided, the class creates a temporary {@code ExecutorService} (that is + * capable of executing all background tasks in parallel) and destroys it at the + * end of background processing. + *

+ *

+ * Alternatively an external {@code ExecutorService} can be provided - either at + * construction time or later by calling the + * {@link #setExternalExecutor(ExecutorService)} method. In this case all + * background tasks are scheduled at this external {@code ExecutorService}. + * Important note: When using an external {@code + * ExecutorService} be sure that the number of threads managed by the service is + * large enough. Otherwise a deadlock can happen! This is the case in the + * following scenario: {@code MultiBackgroundInitializer} starts a task that + * starts all registered {@code BackgroundInitializer} objects and waits for + * their completion. If for instance a single threaded {@code ExecutorService} + * is used, none of the background tasks can be executed, and the task created + * by {@code MultiBackgroundInitializer} waits forever. + *

+ * + * @since 3.0 + */ +public class MultiBackgroundInitializer + extends + BackgroundInitializer { + /** A map with the child initializers. */ + private final Map> childInitializers = + new HashMap>(); + + /** + * Creates a new instance of {@code MultiBackgroundInitializer}. + */ + public MultiBackgroundInitializer() { + super(); + } + + /** + * Creates a new instance of {@code MultiBackgroundInitializer} and + * initializes it with the given external {@code ExecutorService}. + * + * @param exec the {@code ExecutorService} for executing the background + * tasks + */ + public MultiBackgroundInitializer(final ExecutorService exec) { + super(exec); + } + + /** + * Adds a new {@code BackgroundInitializer} to this object. When this + * {@code MultiBackgroundInitializer} is started, the given initializer will + * be processed. This method must not be called after {@link #start()} has + * been invoked. + * + * @param name the name of the initializer (must not be null) + * @param init the {@code BackgroundInitializer} to add (must not be + * null) + * @throws IllegalArgumentException if a required parameter is missing + * @throws IllegalStateException if {@code start()} has already been called + */ +/** + * Adds a new {@code BackgroundInitializer} to this object. When this + * {@code MultiBackgroundInitializer} is started, the given initializer will + * be processed. This method must not be called after {@link #start()} has + * been invoked. + * + * @param name + * the name of the initializer (must not be null) + * @param init + * the {@code BackgroundInitializer} to add (must not be + * null) + * @throws IllegalArgumentException + * if a required parameter is missing + * @throws IllegalStateException + * if {@code start()} has already been called + */ +public void addInitializer(final java.lang.String name, final org.apache.commons.lang3.concurrent.BackgroundInitializer init) { + if (name == null) { + throw new java.lang.IllegalArgumentException("Name of child initializer must not be null!"); + } + { + synchronized(this) { + if (isStarted()) { + throw new java.lang.IllegalStateException("addInitializer() must not be called after start()!"); + } + childInitializers.put(name, /* NPEX_NULL_EXP */ + init); + } + } +} + + /** + * Returns the number of tasks needed for executing all child {@code + * BackgroundInitializer} objects in parallel. This implementation sums up + * the required tasks for all child initializers (which is necessary if one + * of the child initializers is itself a {@code MultiBackgroundInitializer} + * ). Then it adds 1 for the control task that waits for the completion of + * the children. + * + * @return the number of tasks required for background processing + */ + @Override + protected int getTaskCount() { + int result = 1; + + for (final BackgroundInitializer bi : childInitializers.values()) { + result += bi.getTaskCount(); + } + + return result; + } + + /** + * Creates the results object. This implementation starts all child {@code + * BackgroundInitializer} objects. Then it collects their results and + * creates a {@code MultiBackgroundInitializerResults} object with this + * data. If a child initializer throws a checked exceptions, it is added to + * the results object. Unchecked exceptions are propagated. + * + * @return the results object + * @throws Exception if an error occurs + */ + @Override + protected MultiBackgroundInitializerResults initialize() throws Exception { + Map> inits; + synchronized (this) { + // create a snapshot to operate on + inits = new HashMap>( + childInitializers); + } + + // start the child initializers + final ExecutorService exec = getActiveExecutor(); + for (final BackgroundInitializer bi : inits.values()) { + if (bi.getExternalExecutor() == null) { + // share the executor service if necessary + bi.setExternalExecutor(exec); + } + bi.start(); + } + + // collect the results + final Map results = new HashMap(); + final Map excepts = new HashMap(); + for (final Map.Entry> e : inits.entrySet()) { + try { + results.put(e.getKey(), e.getValue().get()); + } catch (final ConcurrentException cex) { + excepts.put(e.getKey(), cex); + } + } + + return new MultiBackgroundInitializerResults(inits, results, excepts); + } + + /** + * A data class for storing the results of the background initialization + * performed by {@code MultiBackgroundInitializer}. Objects of this inner + * class are returned by {@link MultiBackgroundInitializer#initialize()}. + * They allow access to all result objects produced by the + * {@link BackgroundInitializer} objects managed by the owning instance. It + * is also possible to retrieve status information about single + * {@link BackgroundInitializer}s, i.e. whether they completed normally or + * caused an exception. + */ + public static class MultiBackgroundInitializerResults { + /** A map with the child initializers. */ + private final Map> initializers; + + /** A map with the result objects. */ + private final Map resultObjects; + + /** A map with the exceptions. */ + private final Map exceptions; + + /** + * Creates a new instance of {@code MultiBackgroundInitializerResults} + * and initializes it with maps for the {@code BackgroundInitializer} + * objects, their result objects and the exceptions thrown by them. + * + * @param inits the {@code BackgroundInitializer} objects + * @param results the result objects + * @param excepts the exceptions + */ + private MultiBackgroundInitializerResults( + final Map> inits, + final Map results, + final Map excepts) { + initializers = inits; + resultObjects = results; + exceptions = excepts; + } + + /** + * Returns the {@code BackgroundInitializer} with the given name. If the + * name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the {@code BackgroundInitializer} with this name + * @throws NoSuchElementException if the name cannot be resolved + */ + public BackgroundInitializer getInitializer(final String name) { + return checkName(name); + } + + /** + * Returns the result object produced by the {@code + * BackgroundInitializer} with the given name. This is the object + * returned by the initializer's {@code initialize()} method. If this + * {@code BackgroundInitializer} caused an exception, null is + * returned. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the result object produced by this {@code + * BackgroundInitializer} + * @throws NoSuchElementException if the name cannot be resolved + */ + public Object getResultObject(final String name) { + checkName(name); + return resultObjects.get(name); + } + + /** + * Returns a flag whether the {@code BackgroundInitializer} with the + * given name caused an exception. + * + * @param name the name of the {@code BackgroundInitializer} + * @return a flag whether this initializer caused an exception + * @throws NoSuchElementException if the name cannot be resolved + */ + public boolean isException(final String name) { + checkName(name); + return exceptions.containsKey(name); + } + + /** + * Returns the {@code ConcurrentException} object that was thrown by the + * {@code BackgroundInitializer} with the given name. If this + * initializer did not throw an exception, the return value is + * null. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the exception thrown by this initializer + * @throws NoSuchElementException if the name cannot be resolved + */ + public ConcurrentException getException(final String name) { + checkName(name); + return exceptions.get(name); + } + + /** + * Returns a set with the names of all {@code BackgroundInitializer} + * objects managed by the {@code MultiBackgroundInitializer}. + * + * @return an (unmodifiable) set with the names of the managed {@code + * BackgroundInitializer} objects + */ + public Set initializerNames() { + return Collections.unmodifiableSet(initializers.keySet()); + } + + /** + * Returns a flag whether the whole initialization was successful. This + * is the case if no child initializer has thrown an exception. + * + * @return a flag whether the initialization was successful + */ + public boolean isSuccessful() { + return exceptions.isEmpty(); + } + + /** + * Checks whether an initializer with the given name exists. If not, + * throws an exception. If it exists, the associated child initializer + * is returned. + * + * @param name the name to check + * @return the initializer with this name + * @throws NoSuchElementException if the name is unknown + */ + private BackgroundInitializer checkName(final String name) { + final BackgroundInitializer init = initializers.get(name); + if (init == null) { + throw new NoSuchElementException( + "No child initializer with name " + name); + } + + return init; + } + } +} diff --git a/Java/commons-lang-MultiBackgroundInitializer_138/metadata.json b/Java/commons-lang-MultiBackgroundInitializer_138/metadata.json new file mode 100644 index 000000000..b5d38e5ad --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_138/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MultiBackgroundInitializer_138", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java", + "line": 159, + "npe_method": "addInitializer", + "deref_field": "init", + "npe_class": "MultiBackgroundInitializer", + "repo": "commons-lang", + "bug_id": "MultiBackgroundInitializer_138" + } +} diff --git a/Java/commons-lang-MultiBackgroundInitializer_138/npe.json b/Java/commons-lang-MultiBackgroundInitializer_138/npe.json new file mode 100644 index 000000000..7c47accce --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_138/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java", + "line": 159, + "npe_method": "addInitializer", + "deref_field": "init", + "npe_class": "MultiBackgroundInitializer" +} \ No newline at end of file diff --git a/Java/commons-lang-MultiBackgroundInitializer_343/Dockerfile b/Java/commons-lang-MultiBackgroundInitializer_343/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_343/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MultiBackgroundInitializer_343/buggy.java b/Java/commons-lang-MultiBackgroundInitializer_343/buggy.java new file mode 100644 index 000000000..9d3f55f4c --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_343/buggy.java @@ -0,0 +1,360 @@ +/* + * 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.commons.lang3.concurrent; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +/** + *

+ * A specialized {@link BackgroundInitializer} implementation that can deal with + * multiple background initialization tasks. + *

+ *

+ * This class has a similar purpose as {@link BackgroundInitializer}. However, + * it is not limited to a single background initialization task. Rather it + * manages an arbitrary number of {@code BackgroundInitializer} objects, + * executes them, and waits until they are completely initialized. This is + * useful for applications that have to perform multiple initialization tasks + * that can run in parallel (i.e. that do not depend on each other). This class + * takes care about the management of an {@code ExecutorService} and shares it + * with the {@code BackgroundInitializer} objects it is responsible for; so the + * using application need not bother with these details. + *

+ *

+ * The typical usage scenario for {@code MultiBackgroundInitializer} is as + * follows: + *

+ *
    + *
  • Create a new instance of the class. Optionally pass in a pre-configured + * {@code ExecutorService}. Alternatively {@code MultiBackgroundInitializer} can + * create a temporary {@code ExecutorService} and delete it after initialization + * is complete.
  • + *
  • Create specialized {@link BackgroundInitializer} objects for the + * initialization tasks to be performed and add them to the {@code + * MultiBackgroundInitializer} using the + * {@link #addInitializer(String, BackgroundInitializer)} method.
  • + *
  • After all initializers have been added, call the {@link #start()} method. + *
  • + *
  • When access to the result objects produced by the {@code + * BackgroundInitializer} objects is needed call the {@link #get()} method. The + * object returned here provides access to all result objects created during + * initialization. It also stores information about exceptions that have + * occurred.
  • + *
+ *

+ * {@code MultiBackgroundInitializer} starts a special controller task that + * starts all {@code BackgroundInitializer} objects added to the instance. + * Before the an initializer is started it is checked whether this initializer + * already has an {@code ExecutorService} set. If this is the case, this {@code + * ExecutorService} is used for running the background task. Otherwise the + * current {@code ExecutorService} of this {@code MultiBackgroundInitializer} is + * shared with the initializer. + *

+ *

+ * The easiest way of using this class is to let it deal with the management of + * an {@code ExecutorService} itself: If no external {@code ExecutorService} is + * provided, the class creates a temporary {@code ExecutorService} (that is + * capable of executing all background tasks in parallel) and destroys it at the + * end of background processing. + *

+ *

+ * Alternatively an external {@code ExecutorService} can be provided - either at + * construction time or later by calling the + * {@link #setExternalExecutor(ExecutorService)} method. In this case all + * background tasks are scheduled at this external {@code ExecutorService}. + * Important note: When using an external {@code + * ExecutorService} be sure that the number of threads managed by the service is + * large enough. Otherwise a deadlock can happen! This is the case in the + * following scenario: {@code MultiBackgroundInitializer} starts a task that + * starts all registered {@code BackgroundInitializer} objects and waits for + * their completion. If for instance a single threaded {@code ExecutorService} + * is used, none of the background tasks can be executed, and the task created + * by {@code MultiBackgroundInitializer} waits forever. + *

+ * + * @since 3.0 + */ +public class MultiBackgroundInitializer + extends + BackgroundInitializer { + /** A map with the child initializers. */ + private final Map> childInitializers = + new HashMap>(); + + /** + * Creates a new instance of {@code MultiBackgroundInitializer}. + */ + public MultiBackgroundInitializer() { + super(); + } + + /** + * Creates a new instance of {@code MultiBackgroundInitializer} and + * initializes it with the given external {@code ExecutorService}. + * + * @param exec the {@code ExecutorService} for executing the background + * tasks + */ + public MultiBackgroundInitializer(final ExecutorService exec) { + super(exec); + } + + /** + * Adds a new {@code BackgroundInitializer} to this object. When this + * {@code MultiBackgroundInitializer} is started, the given initializer will + * be processed. This method must not be called after {@link #start()} has + * been invoked. + * + * @param name the name of the initializer (must not be null) + * @param init the {@code BackgroundInitializer} to add (must not be + * null) + * @throws IllegalArgumentException if a required parameter is missing + * @throws IllegalStateException if {@code start()} has already been called + */ + public void addInitializer(final String name, final BackgroundInitializer init) { + if (name == null) { + throw new IllegalArgumentException( + "Name of child initializer must not be null!"); + } + if (init == null) { + throw new IllegalArgumentException( + "Child initializer must not be null!"); + } + + synchronized (this) { + if (isStarted()) { + throw new IllegalStateException( + "addInitializer() must not be called after start()!"); + } + childInitializers.put(name, init); + } + } + + /** + * Returns the number of tasks needed for executing all child {@code + * BackgroundInitializer} objects in parallel. This implementation sums up + * the required tasks for all child initializers (which is necessary if one + * of the child initializers is itself a {@code MultiBackgroundInitializer} + * ). Then it adds 1 for the control task that waits for the completion of + * the children. + * + * @return the number of tasks required for background processing + */ + @Override + protected int getTaskCount() { + int result = 1; + + for (final BackgroundInitializer bi : childInitializers.values()) { + result += bi.getTaskCount(); + } + + return result; + } + + /** + * Creates the results object. This implementation starts all child {@code + * BackgroundInitializer} objects. Then it collects their results and + * creates a {@code MultiBackgroundInitializerResults} object with this + * data. If a child initializer throws a checked exceptions, it is added to + * the results object. Unchecked exceptions are propagated. + * + * @return the results object + * @throws Exception if an error occurs + */ + @Override + protected MultiBackgroundInitializerResults initialize() throws Exception { + Map> inits; + synchronized (this) { + // create a snapshot to operate on + inits = new HashMap>( + childInitializers); + } + + // start the child initializers + final ExecutorService exec = getActiveExecutor(); + for (final BackgroundInitializer bi : inits.values()) { + if (bi.getExternalExecutor() == null) { + // share the executor service if necessary + bi.setExternalExecutor(exec); + } + bi.start(); + } + + // collect the results + final Map results = new HashMap(); + final Map excepts = new HashMap(); + for (final Map.Entry> e : inits.entrySet()) { + try { + results.put(e.getKey(), e.getValue().get()); + } catch (final ConcurrentException cex) { + excepts.put(e.getKey(), cex); + } + } + + return new MultiBackgroundInitializerResults(inits, results, excepts); + } + + /** + * A data class for storing the results of the background initialization + * performed by {@code MultiBackgroundInitializer}. Objects of this inner + * class are returned by {@link MultiBackgroundInitializer#initialize()}. + * They allow access to all result objects produced by the + * {@link BackgroundInitializer} objects managed by the owning instance. It + * is also possible to retrieve status information about single + * {@link BackgroundInitializer}s, i.e. whether they completed normally or + * caused an exception. + */ + public static class MultiBackgroundInitializerResults { + /** A map with the child initializers. */ + private final Map> initializers; + + /** A map with the result objects. */ + private final Map resultObjects; + + /** A map with the exceptions. */ + private final Map exceptions; + + /** + * Creates a new instance of {@code MultiBackgroundInitializerResults} + * and initializes it with maps for the {@code BackgroundInitializer} + * objects, their result objects and the exceptions thrown by them. + * + * @param inits the {@code BackgroundInitializer} objects + * @param results the result objects + * @param excepts the exceptions + */ + private MultiBackgroundInitializerResults( + final Map> inits, + final Map results, + final Map excepts) { + initializers = inits; + resultObjects = results; + exceptions = excepts; + } + + /** + * Returns the {@code BackgroundInitializer} with the given name. If the + * name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the {@code BackgroundInitializer} with this name + * @throws NoSuchElementException if the name cannot be resolved + */ + public BackgroundInitializer getInitializer(final String name) { + return checkName(name); + } + + /** + * Returns the result object produced by the {@code + * BackgroundInitializer} with the given name. This is the object + * returned by the initializer's {@code initialize()} method. If this + * {@code BackgroundInitializer} caused an exception, null is + * returned. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the result object produced by this {@code + * BackgroundInitializer} + * @throws NoSuchElementException if the name cannot be resolved + */ + public Object getResultObject(final String name) { + checkName(name); + return resultObjects.get(name); + } + + /** + * Returns a flag whether the {@code BackgroundInitializer} with the + * given name caused an exception. + * + * @param name the name of the {@code BackgroundInitializer} + * @return a flag whether this initializer caused an exception + * @throws NoSuchElementException if the name cannot be resolved + */ + public boolean isException(final String name) { + checkName(name); + return exceptions.containsKey(name); + } + + /** + * Returns the {@code ConcurrentException} object that was thrown by the + * {@code BackgroundInitializer} with the given name. If this + * initializer did not throw an exception, the return value is + * null. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the exception thrown by this initializer + * @throws NoSuchElementException if the name cannot be resolved + */ + public ConcurrentException getException(final String name) { + checkName(name); + return exceptions.get(name); + } + + /** + * Returns a set with the names of all {@code BackgroundInitializer} + * objects managed by the {@code MultiBackgroundInitializer}. + * + * @return an (unmodifiable) set with the names of the managed {@code + * BackgroundInitializer} objects + */ + public Set initializerNames() { + return Collections.unmodifiableSet(initializers.keySet()); + } + + /** + * Returns a flag whether the whole initialization was successful. This + * is the case if no child initializer has thrown an exception. + * + * @return a flag whether the initialization was successful + */ + public boolean isSuccessful() { + return exceptions.isEmpty(); + } + + /** + * Checks whether an initializer with the given name exists. If not, + * throws an exception. If it exists, the associated child initializer + * is returned. + * + * @param name the name to check + * @return the initializer with this name + * @throws NoSuchElementException if the name is unknown + */ +/** + * Checks whether an initializer with the given name exists. If not, + * throws an exception. If it exists, the associated child initializer + * is returned. + * + * @param name + * the name to check + * @return the initializer with this name + * @throws NoSuchElementException + * if the name is unknown + */ +private org.apache.commons.lang3.concurrent.BackgroundInitializer checkName(final java.lang.String name) { + final org.apache.commons.lang3.concurrent.BackgroundInitializer init = initializers.get(name); + { + return /* NPEX_NULL_EXP */ + init; + } +} + } +} diff --git a/Java/commons-lang-MultiBackgroundInitializer_343/metadata.json b/Java/commons-lang-MultiBackgroundInitializer_343/metadata.json new file mode 100644 index 000000000..9fa528939 --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_343/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MultiBackgroundInitializer_343", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java", + "line": 356, + "npe_method": "checkName", + "deref_field": "init", + "npe_class": "MultiBackgroundInitializerResults", + "repo": "commons-lang", + "bug_id": "MultiBackgroundInitializer_343" + } +} diff --git a/Java/commons-lang-MultiBackgroundInitializer_343/npe.json b/Java/commons-lang-MultiBackgroundInitializer_343/npe.json new file mode 100644 index 000000000..591dd4495 --- /dev/null +++ b/Java/commons-lang-MultiBackgroundInitializer_343/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java", + "line": 356, + "npe_method": "checkName", + "deref_field": "init", + "npe_class": "MultiBackgroundInitializerResults" +} \ No newline at end of file diff --git a/Java/commons-lang-MutableObject_113/Dockerfile b/Java/commons-lang-MutableObject_113/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MutableObject_113/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MutableObject_113/buggy.java b/Java/commons-lang-MutableObject_113/buggy.java new file mode 100644 index 000000000..00931cb3c --- /dev/null +++ b/Java/commons-lang-MutableObject_113/buggy.java @@ -0,0 +1,133 @@ +/* + * 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.commons.lang3.mutable; + +import java.io.Serializable; + +/** + * A mutable Object wrapper. + * + * @param the type to set and get + * @since 2.1 + */ +public class MutableObject implements Mutable, Serializable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 86241875189L; + + /** The mutable value. */ + private T value; + + /** + * Constructs a new MutableObject with the default value of null. + */ + public MutableObject() { + super(); + } + + /** + * Constructs a new MutableObject with the specified value. + * + * @param value the initial value to store + */ + public MutableObject(final T value) { + super(); + this.value = value; + } + + //----------------------------------------------------------------------- + /** + * Gets the value. + * + * @return the value, may be null + */ + @Override + public T getValue() { + return this.value; + } + + /** + * Sets the value. + * + * @param value the value to set + */ + @Override + public void setValue(final T value) { + this.value = value; + } + + //----------------------------------------------------------------------- + /** + *

+ * Compares this object against the specified object. The result is true if and only if the argument + * is not null and is a MutableObject object that contains the same T + * value as this object. + *

+ * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; + * true if the objects have equivalent value fields; + * false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (this.getClass() == obj.getClass()) { + final MutableObject that = (MutableObject) obj; + return this.value.equals(that.value); + } + return false; + } + + /** + * Returns the value's hash code or 0 if the value is null. + * + * @return the value's hash code or 0 if the value is null. + */ + @Override +/** + * Returns the value's hash code or 0 if the value is null. + * + * @return the value's hash code or 0 if the value is null. + */ +public int hashCode() { + return /* NPEX_NULL_EXP */ + value.hashCode(); +} + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return value == null ? "null" : value.toString(); + } + +} diff --git a/Java/commons-lang-MutableObject_113/metadata.json b/Java/commons-lang-MutableObject_113/metadata.json new file mode 100644 index 000000000..da8e77d25 --- /dev/null +++ b/Java/commons-lang-MutableObject_113/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MutableObject_113", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/mutable/MutableObject.java", + "line": 119, + "npe_method": "hashCode", + "deref_field": "value", + "npe_class": "MutableObject", + "repo": "commons-lang", + "bug_id": "MutableObject_113" + } +} diff --git a/Java/commons-lang-MutableObject_113/npe.json b/Java/commons-lang-MutableObject_113/npe.json new file mode 100644 index 000000000..262daf277 --- /dev/null +++ b/Java/commons-lang-MutableObject_113/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/mutable/MutableObject.java", + "line": 119, + "npe_method": "hashCode", + "deref_field": "value", + "npe_class": "MutableObject" +} \ No newline at end of file diff --git a/Java/commons-lang-MutableObject_124/Dockerfile b/Java/commons-lang-MutableObject_124/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MutableObject_124/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MutableObject_124/buggy.java b/Java/commons-lang-MutableObject_124/buggy.java new file mode 100644 index 000000000..1208ad33a --- /dev/null +++ b/Java/commons-lang-MutableObject_124/buggy.java @@ -0,0 +1,134 @@ +/* + * 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.commons.lang3.mutable; + +import java.io.Serializable; + +/** + * A mutable Object wrapper. + * + * @param the type to set and get + * @since 2.1 + */ +public class MutableObject implements Mutable, Serializable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 86241875189L; + + /** The mutable value. */ + private T value; + + /** + * Constructs a new MutableObject with the default value of null. + */ + public MutableObject() { + super(); + } + + /** + * Constructs a new MutableObject with the specified value. + * + * @param value the initial value to store + */ + public MutableObject(final T value) { + super(); + this.value = value; + } + + //----------------------------------------------------------------------- + /** + * Gets the value. + * + * @return the value, may be null + */ + @Override + public T getValue() { + return this.value; + } + + /** + * Sets the value. + * + * @param value the value to set + */ + @Override + public void setValue(final T value) { + this.value = value; + } + + //----------------------------------------------------------------------- + /** + *

+ * Compares this object against the specified object. The result is true if and only if the argument + * is not null and is a MutableObject object that contains the same T + * value as this object. + *

+ * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; + * true if the objects have equivalent value fields; + * false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (this.getClass() == obj.getClass()) { + final MutableObject that = (MutableObject) obj; + return this.value.equals(that.value); + } + return false; + } + + /** + * Returns the value's hash code or 0 if the value is null. + * + * @return the value's hash code or 0 if the value is null. + */ + @Override + public int hashCode() { + return value == null ? 0 : value.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override +// ----------------------------------------------------------------------- +/** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ +public java.lang.String toString() { + return /* NPEX_NULL_EXP */ + value.toString(); +} + +} diff --git a/Java/commons-lang-MutableObject_124/metadata.json b/Java/commons-lang-MutableObject_124/metadata.json new file mode 100644 index 000000000..8a982200a --- /dev/null +++ b/Java/commons-lang-MutableObject_124/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MutableObject_124", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/mutable/MutableObject.java", + "line": 131, + "npe_method": "toString", + "deref_field": "value", + "npe_class": "MutableObject", + "repo": "commons-lang", + "bug_id": "MutableObject_124" + } +} diff --git a/Java/commons-lang-MutableObject_124/npe.json b/Java/commons-lang-MutableObject_124/npe.json new file mode 100644 index 000000000..c9ad38fca --- /dev/null +++ b/Java/commons-lang-MutableObject_124/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/mutable/MutableObject.java", + "line": 131, + "npe_method": "toString", + "deref_field": "value", + "npe_class": "MutableObject" +} \ No newline at end of file diff --git a/Java/commons-lang-MutableObject_93/Dockerfile b/Java/commons-lang-MutableObject_93/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-MutableObject_93/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-MutableObject_93/buggy.java b/Java/commons-lang-MutableObject_93/buggy.java new file mode 100644 index 000000000..fa6e002ea --- /dev/null +++ b/Java/commons-lang-MutableObject_93/buggy.java @@ -0,0 +1,141 @@ +/* + * 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.commons.lang3.mutable; + +import java.io.Serializable; + +/** + * A mutable Object wrapper. + * + * @param the type to set and get + * @since 2.1 + */ +public class MutableObject implements Mutable, Serializable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 86241875189L; + + /** The mutable value. */ + private T value; + + /** + * Constructs a new MutableObject with the default value of null. + */ + public MutableObject() { + super(); + } + + /** + * Constructs a new MutableObject with the specified value. + * + * @param value the initial value to store + */ + public MutableObject(final T value) { + super(); + this.value = value; + } + + //----------------------------------------------------------------------- + /** + * Gets the value. + * + * @return the value, may be null + */ + @Override + public T getValue() { + return this.value; + } + + /** + * Sets the value. + * + * @param value the value to set + */ + @Override + public void setValue(final T value) { + this.value = value; + } + + //----------------------------------------------------------------------- + /** + *

+ * Compares this object against the specified object. The result is true if and only if the argument + * is not null and is a MutableObject object that contains the same T + * value as this object. + *

+ * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; + * true if the objects have equivalent value fields; + * false otherwise. + */ + @Override +// ----------------------------------------------------------------------- +/** + *

+ * Compares this object against the specified object. The result is true if and only if the argument + * is not null and is a MutableObject object that contains the same T + * value as this object. + *

+ * + * @param obj + * the object to compare with, null returns false + * @return true if the objects are the same; +true if the objects have equivalent value fields; +false otherwise. + */ +public boolean equals(final java.lang.Object obj) { + { + if (this == /* NPEX_NULL_EXP */ + obj) { + return true; + } + if (this.getClass() == obj.getClass()) { + final org.apache.commons.lang3.mutable.MutableObject that = ((org.apache.commons.lang3.mutable.MutableObject) (obj)); + return this.value.equals(that.value); + } + return false; + } +} + + /** + * Returns the value's hash code or 0 if the value is null. + * + * @return the value's hash code or 0 if the value is null. + */ + @Override + public int hashCode() { + return value == null ? 0 : value.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return value == null ? "null" : value.toString(); + } + +} diff --git a/Java/commons-lang-MutableObject_93/metadata.json b/Java/commons-lang-MutableObject_93/metadata.json new file mode 100644 index 000000000..636bbfc2e --- /dev/null +++ b/Java/commons-lang-MutableObject_93/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-MutableObject_93", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/mutable/MutableObject.java", + "line": 109, + "npe_method": "equals", + "deref_field": "obj", + "npe_class": "MutableObject", + "repo": "commons-lang", + "bug_id": "MutableObject_93" + } +} diff --git a/Java/commons-lang-MutableObject_93/npe.json b/Java/commons-lang-MutableObject_93/npe.json new file mode 100644 index 000000000..78b77a760 --- /dev/null +++ b/Java/commons-lang-MutableObject_93/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/mutable/MutableObject.java", + "line": 109, + "npe_method": "equals", + "deref_field": "obj", + "npe_class": "MutableObject" +} \ No newline at end of file