-1

For a programming practical task, we are given an example .class file. We need to print out all methods that take 1 x int input and some printable output, and then allow the user to run that method with one input as given through the command line. However, when I try to invoke the method, an IllegalArgumentException is thrown.

My code that throws the exception:

// Request the user enter an integer and run the requested method.
private static void methodInvoke(Method inMethod, Class methodClass, Scanner scanner) throws 
NumberFormatException,IllegalAccessException,InvocationTargetException,InstantiationException,ClassNotFoundException
{
    Integer userNumber = 0;
    Object methodObject = methodClass.newInstance();

    System.out.println(inMethod.toString()); // Test to confirm printing the correct method.

    System.out.println("Enter a number to supply to: '" + inMethod.toString() + ":");
    userNumber = Integer.getInteger(scanner.nextLine());

    System.out.println(inMethod.invoke(methodObject, userNumber)); // Throws IllegalArgumentException here.
}

As some fail-safe checks I've done the following:

  • Printed the integer to confirm scanner reads it correctly.
  • Tested on an example file for which I know the code:

public class TestFile
{
    public int testMethod(int testInt)
    {
        return 2*testInt;
    }
}

Command line output when it occurs:

Enter a number to supply to: 'public int TestFile.testMethod(int):
1
Error: Invalid argument.
java.lang.IllegalArgumentException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at MethodMetrics.methodInvoke(MethodMetrics.java:79)
    at MethodMetrics.main(MethodMetrics.java:29)

Any ideas as to the cause would be appreciated. Am I missing something obvious? :)

EDIT: Here's the code that selects the methods:

private static Method[] getIntMethods(Class classToTest) throws NullPointerException
    {
        int counter = 0;
        Method[] allFoundMethods = classToTest.getDeclaredMethods(); // Unnecessary to check for SecurityException here
        Method[] returnMethods = new Method[allFoundMethods.length];

        if(returnMethods.length > 0) // Only bother if the class has methods.
        {   
            for(Method mTest : allFoundMethods)
            {
                if(mTest.getParameterTypes().length == 1)
                {
                    if(mTest.getParameterTypes()[0].getName().equals("int"))
                    {
                        returnMethods[counter++] = mTest;
                    }
                }
            }
            returnMethods = Arrays.copyOf(returnMethods, counter);
        }

        return returnMethods;
    }

AND where "methodInvoke" is called from the main method:

System.out.println("Select a method with the method index from above: '(0) to (n-1)':");
selectedMethod = scanner.nextLine();
methodInvoke(foundMethods[Integer.parseInt(selectedMethod)], scanner);
Ben Palmer
  • 131
  • 2
  • 12
  • 1
    and which line is 86 – strash Apr 22 '17 at 11:51
  • Hey @gen.Strash I've commented that in the first code block, it's the last line. :) – Ben Palmer Apr 22 '17 at 11:53
  • 2
    Clearly `inMethod` isn't expecting an `Integer` (or `int`) as its first argument. Since you haven't shown us how you get `inMethod`, we can't really help. If it really referenced a method accepting a single `Integer` or `int`, it would work. – T.J. Crowder Apr 22 '17 at 11:54
  • @T.J.Crowder i've edited the question to show how I select the method and where the function is called. – Ben Palmer Apr 22 '17 at 12:01
  • 1
    Instead of printing `inMethod.getName() + "(int)"`, try printing `inMethod` itself, which will print the full method signature, and we'll *all* know exactly what method you're trying to invoke. – Andreas Apr 22 '17 at 12:03
  • 3
    Why are you doing `Class.forName(inMethod.getDeclaringClass().getName())`, when `inMethod.getDeclaringClass()` is already the `Class` object you're looking for? --- And why are you printing the constructors, when `newInstance()` would have already failed if no no-arg/default constructor exists? – Andreas Apr 22 '17 at 12:05
  • @Andreas sure I've fixed the bits of code where I was doing nonsensical things. With the suggestion given, the full method signature is printed by "inMethod.toString()" and gives "public int TestFile.testMethod(int) ", so it is indeed the correct method. – Ben Palmer Apr 22 '17 at 12:20
  • 1
    The following runs just fine: https://ideone.com/94RmO3 – Mike Nakis Apr 22 '17 at 12:26
  • Thank you all. Much appreciated. Learned a few things about how not to use the Integer class tonight. ;) – Ben Palmer Apr 22 '17 at 12:35

1 Answers1

3

Your call is failing because you're passing a null value to an int parameter.

Javadoc of invoke() says:

Throws IllegalArgumentException if the method is an instance method and the specified object argument is not an instance of the class or interface declaring the underlying method (or of a subclass or implementor thereof); if the number of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion.

Since converting null to int fails, you get IllegalArgumentException.

The reason you have a null value, is that you're calling the wrong method. Javadoc of Integer.getInteger(String nm) says:

Determines the integer value of the system property with the specified name.

If there is no property with the specified name, if the specified name is empty or null, or if the property does not have the correct numeric format, then null is returned.

Solution: You should be calling Integer.valueOf(String s).

Returns an Integer object holding the value of the specified String. The argument is interpreted as representing a signed decimal integer.

Community
  • 1
  • 1
Andreas
  • 154,647
  • 11
  • 152
  • 247