Jacob Asmuth
Jacob Asmuth

Reputation: 21

Unhandled exception: NoSuchMethodException

I'm trying to write my own implementation of the Miller Rabin primality test. I could get it working, but it was very slow for values larger than 64 bits.

In the draft standard ANSI X9.80, "PRIME NUMBER GENERATION, PRIMALITY TESTING, AND PRIMALITY CERTIFICATES", they specify behavior up to 1024 bits. My program (on a i7 6700k) would take months at best to run on a single 1024 bit integer.

So I turned to the java implementation of the Miller Rabin test to see what micro-optimizations they used to make the performance tenable.

I've been working my way through their source code, but I've run up against a wall. A lot of the methods they use are private, and testing your codes behavior against code you can't execute is quite difficult.For starters, the first internal method I wanted to call is BigInteger.mod2( int )

I've not programmed extensively in java before, but here's where I got stuck:

import java.lang.reflect.*;
import java.math.BigInteger;

public class HelloWorld
{
    public static void main(String[] args)
    {
        BigInteger a = new BigInteger( "123456789101112" );
        Method mod2 = BigInteger.class.getDeclaredMethod( "mod2", int.class );
        //Class[] arg_types = new Class[1];
        //arg_types[0] = int.class;
        //Method mod2 = BigInteger.class.getDeclaredMethod( "mod2", arg_types );
        mod2.setAccessible( true );
        Object b = mod2.invoke( a, 32 );
        System.out.print( b );
    }
}

Both version of the 'getDeclaredMethod' call throw NoSuchMethodException exceptions. I've looked at the documentation for 'getDeclaredMethod' and they say to do exactly what I'm currently doing when people are asking how to get this function to work.

Any advice on how to invoke the private methods of BigInteger, in particular BigInteger.mod2( int ) would be greatly appreciated. Thanks!

Upvotes: 1

Views: 2617

Answers (2)

teppic
teppic

Reputation: 7286

In your example you've failed to handle the checked exceptions that getDeclaredMethod may raise. Change the signature to

public static void main(String[] args) throws Exception {

After that your code should be working. If getDeclaredMethod still raises a NoSuchMethodException then there really isn't a mod2 method in the BigInteger that you're linking against.

This will happen if you run against a JDK with a BigInteger that doesn't have a method with the signature private mod2(int). Gnu classpath, for example, doesn't have one.

Upvotes: 1

VHS
VHS

Reputation: 10184

You are on the right track. The only way to invoke private methods in Java is using reflection API. You are already using it. The only error in your program is that you are not handling the checked exception. Just surround your getDeclaredMethod call and method invocation calls with try-catch and you are good to go.

    BigInteger a = new BigInteger( "123456789101112" );
    Method mod2 = null;
    try {
        mod2 = BigInteger.class.getDeclaredMethod( "mod2", int.class );
    } catch (NoSuchMethodException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    //Class[] arg_types = new Class[1];
    //arg_types[0] = int.class;
    //Method mod2 = BigInteger.class.getDeclaredMethod( "mod2", arg_types );
    mod2.setAccessible( true );
    Object b;
    try {
        b = mod2.invoke( a, 32 );
           System.out.print( b );
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Read the Javadoc for the method Class::getDeclaredMethod. It says that this method throws two exceptions (1) NoSuchMethodException and (2) SecurityException.

Same way, read the Javadoc for the method Method::invoke. It says that this method throws three exceptions (1) IllegalAccessException (2) IllegalArgumentException (3) InvocationTargetException.

The calling method of these methods must catch these exceptions or add a throws clause to its own method signature listing out all these exceptions that it is not handling.

Upvotes: 4

Related Questions