RobotRock
RobotRock

Reputation: 4449

Java generic method for primitives

I have a very creative solution to allow my unsigned code all access through my signed library. Although bad practice, I fear I have no other solution (except rewriting a lot of code, that then needs to be rewrited back).

I have the following class:

public abstract class full {
    public static <T,S,P> S access(final T object, final String function, final P parameter) {
        AccessController.doPrivileged(new PrivilegedAction<S>() {
            @Override
            public S run() {
                try {
                    if (parameter == null) {
                        Class[] argTypes = { };
                        Object passedArgv[] = { };
                        return (S)object.getClass().getMethod(function, argTypes).invoke(object, passedArgv);
                    } else {
                        Class[] argTypes = { parameter.getClass() };
                        Object passedArgv[] = { parameter };
                        return (S)object.getClass().getMethod(function, argTypes).invoke(object, passedArgv);
                    }
                } catch (NoSuchMethodException ex) {
                    Logger.getLogger(full.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SecurityException ex) {
                    Logger.getLogger(full.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(full.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InvocationTargetException ex) {
                    Logger.getLogger(full.class.getName()).log(Level.SEVERE, null, ex);
                }
                return null;
            }
        });
        return null;
    }
}

It works great for functions that return Objects, but not for primitives. Boolean bool = full.access(..); will result in a nullpointer, because generic methods can't handle primitives.

Any ideas about how to take the right approach?

To test:

public static Boolean test() {
    return true;
}

public Main() {
    System.out.println(((Boolean)redirect.full.access(this, "test", null)));
}

Upvotes: 2

Views: 1393

Answers (2)

nicholas.hauschild
nicholas.hauschild

Reputation: 42849

The reason you are getting a NullPointerException is because you are always returning null. You call doPrivileged(...), yet null is still returned. Try returning the output of doPrivileged(...). By the looks of things, Auto(un)boxing is working here on both the inputs and the returned outputs.

This worked for me (I passed in a primitive int, and expected a primitive boolean):

public class ATest
{
    public static void main(String[] args) throws UnsupportedEncodingException
    {
        int i = 5;
        Object equals = new Object();

        boolean b = full.access(i, "equals", equals);

        System.out.println(b);
    }

    public static class full
    {
        public static <T, S, P> S access(final T object, final String function, final P parameter)
        {
            return AccessController.doPrivileged(new PrivilegedAction<S>()
            {
                @Override
                public S run()
                {
                    try
                    {
                        if (parameter == null)
                        {
                            Class[] argTypes = {};
                            Object passedArgv[] = {};
                            return (S) object.getClass().getMethod(function, argTypes)
                                    .invoke(object, passedArgv);
                        }
                        else
                        {
                            Class[] argTypes = { parameter.getClass() };
                            Object passedArgv[] = { parameter };
                            return (S) object.getClass().getMethod(function, argTypes)
                                    .invoke(object, passedArgv);
                        }
                    }
                    catch (NoSuchMethodException ex)
                    {
                        Logger.getLogger(full.class.getName()).log(Level.ALL, null, ex);
                    }
                    catch (SecurityException ex)
                    {
                        Logger.getLogger(full.class.getName()).log(Level.ALL, null, ex);
                    }
                    catch (IllegalAccessException ex)
                    {
                        Logger.getLogger(full.class.getName()).log(Level.ALL, null, ex);
                    }
                    catch (InvocationTargetException ex)
                    {
                        Logger.getLogger(full.class.getName()).log(Level.ALL, null, ex);
                    }
                    return null;
                }
            });
        }
    }
}

On another note, you could make this more robust. When I passed in an Integer instead of an Object, the equals method was not found, even though it would have been a valid method call. If you do not find the method with the given Class, you should check again with the classes' parent classes.

Upvotes: 1

user296828
user296828

Reputation:

Isn't that what the primitive classes are for? ( Boolean, Integer... ) I'm not sure if they'll do it, I haven't checked.

Long answer : make a clone of all those methods to return primitives.

Or much shorter; you could just wrap the primitive type you want in an object, that is do something like:

public class MyInt {
    public int intValue;
}

Upvotes: 1

Related Questions