简体   繁体   中英

Why these errors while invoking main through reflection

Here is a custom executor that executes an application by searching for its main in the loaded classes loaded by a custom loader. There is a problem when I try to execute a program using my executor.

The source code of the program being executed can be located on the following link

http://agile.csc.ncsu.edu/SEMaterials/realestate/code/RealEstate.zip

package executorOfLoaderClasses;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import customClassLoader.ClassLoaderOfExtClass;



/**
 * @author Sanyam
 *         
 *         sanyamgoyal007@gmail.com
 */

public class ClassExecutor{

    private ClassLoaderOfExtClass classLoader;
    private byte[][] ArrayOfClasses;
    private String[] ArrayOfBinaryNames;
    @SuppressWarnings("rawtypes")
    private ArrayList<Class> loadedClasses;
    private ArrayList<String> loadedClasesNames;
    private Object[] parameters;


    @SuppressWarnings("rawtypes")
    public ClassExecutor() {
        classLoader = new ClassLoaderOfExtClass();
        new ArrayList<Class>();
        loadedClasses = new ArrayList<Class>();
        loadedClasesNames = new ArrayList<String>();
    }

    @SuppressWarnings("unchecked")
    public void execute(File[] file, String[] binaryPaths) {
        Object[] actuals = { new String[] { "" } };
        Method m = null;
        try {
            Field classesx=ClassLoaderOfExtClass.class.getDeclaredField("classes");
            classesx.setAccessible(true);
        } catch (SecurityException e1) {
            e1.printStackTrace();
        } catch (NoSuchFieldException e1) { 
            e1.printStackTrace();
        }


        /*for (int i = 0; i < file.length; i++) {
            for (int j = 0; j < file.length; j++) {

                try {

                    @SuppressWarnings("rawtypes")
                    Class c = classLoader.loadClassCustom(file[i], binaryPaths[i]);
                //Fied classex=classLoader.getResource("classes");
                }catch(Exception e){

                }

            }
        }
        Class<?>[]classesxx= getLoadedClasses(classLoader);
        System.out.println("Loaded classes have size "+ classesxx.length);*/

        for (int i = 0; i < file.length; i++) {
            try {
                @SuppressWarnings("rawtypes")
                Class c = classLoader.loadClassCustom(file[i], binaryPaths[i]);

                try {
                    if (c.getMethod("main", new Class[] { String[].class }) != null) {
                        m = c.getMethod("main", new Class[] { String[].class });
                    } else {

                        System.out.println("This class does not contain main");
                        continue;
                    }

                } catch (NoSuchMethodException e) {
                //  System.out.println("Main not found!!!");
                    // System.out.println("M here");
                    // e.printStackTrace(); // not printing stack trace
                } catch (SecurityException e) {
                    e.printStackTrace();
                }

            } catch (ClassNotFoundException e) {
                System.out.println("No such class definition exist!!");
                // TODO Auto-generated catch block
                // e.printStackTrace();
            }

        }

        try {

            m.invoke(null, actuals);

            // CallStack.print();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @SuppressWarnings({ })
    public void execute(ArrayList<byte[]> stuffedFiles,
            ArrayList<String> binaryPaths) {
        convertToArray(stuffedFiles, binaryPaths);
        loadAllClasses(ArrayOfClasses, ArrayOfBinaryNames);
        Thread myThread = new MyThread();
        myThread.start();
        /*Object[] actuals = { new String[] { "" } };
        Method m = null;


         * Method[] m1= new Method[10]; for (Class c : loadedClasses) {
         * m1=c.getMethods(); } for(Method m2: m1){
         * System.out.println(m2.getName()); }

         System.out.println(loadedClasses.size()); 
        for (Class c : loadedClasses) {

             * System.out.println(c.toString());
             * System.out.println(c.getConstructors());

            // for (int i = 1; i < file.size(); i++) {

             * for(Method meth : c.getMethods()){ meth.setAccessible(true);
             * 
             * }


            try {
                if (c.getMethod("main", new Class[] { String[].class }) != null) {
                    m = c.getMethod("main", new Class[] { String[].class });
                    break;
                } else {

                //  System.out.println("This class does not contain main");
                    continue;
                }

            } catch (NoSuchMethodException e) {

                System.out.println("Program does not contain main");

            } catch (SecurityException e) {
                e.printStackTrace();
            }

        }

        try {

            if(parameters==null){

            m.invoke(null, actuals);
            }
            else{
                try {

                    System.out.println("It Fails Here");
                    m.invoke(null, parameters);
                } catch (Exception e) {
                    System.out.println("Illegal arguments");
                }
            }

            // CallStack.print();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }*/
// remove till here
        /*TraceParser pr = new TraceParser();
        pr.traceCollector();
        pr.traceStruct();
         ArrayList<SingleTraceStructure> parsedExpressions = pr
            .getTracedObjects();
        AllStackTraceValidator validator = new AllStackTraceValidator(
                parsedExpressions);
        finalObjects = validator.getTraceObjects();

        for(SingleTraceStructure ob : finalObjects){
            validatedTraceObjects.add(ob);
        }
        TraceObjectsMinimizer tracerObj = new TraceObjectsMinimizer();
        tracerObj.sortObjects(finalObjects);*/

        /*
         * for(SingleTraceStructure obj : finalObjects){
         * System.out.println(obj.getCalledBy());
         * System.out.println(obj.getClassName()+":"+obj.getMethodName()+":"+
         * obj.getCallSequenceNumbr()+obj.getCalledBy()); }
         */
    }



    private void convertToArray(ArrayList<byte[]> classes,
            ArrayList<String> binaryPaths) {
        /* = new byte[classes.size()][]; */

        ArrayOfClasses = new byte[classes.size()][];
        ArrayOfBinaryNames = new String[binaryPaths.size()];

        int i = 0;
        for (byte[] tempClass : classes) {
            ArrayOfClasses[i] = tempClass;
            i++;
        }

        int j = 0;
        for (String name : binaryPaths) {
            ArrayOfBinaryNames[j] = name;
            j++;
        }

    }

    @SuppressWarnings("rawtypes")
    public void loadAllClasses(byte[][] classes, String[] names) {


        for (int i = 0; i < classes.length; i++) {
            System.out.println("Round ----->" + i);
            Class c = null;

            for (int j = 0; j < classes.length; j++) {
                if (classes[j] != null) {
                    try {
                        c = classLoader.loadClassCustom(classes[j], names[j]);
                    } catch (ClassNotFoundException e) {
                        // TODO Auto-generated catch block
                        System.out.println("unsucessful");
                        e.printStackTrace();
                    }
                    if (c != null) {
                        System.out.println("loading successfull");
                        loadedClasses.add(c);
                        loadedClasesNames.add(names[j]);
                        classes[j] = null;
                        names[j] = null;
                    } else {
                        // move on
                    }
                } else {
                    // do nothing
                }

            }
        }
    }



    @SuppressWarnings("rawtypes")
    public ArrayList<Class> getLoadedClasses() {
        return loadedClasses;
    }

    public void parametersToMain(ArrayList<String> strs){

        if(strs!=null){
        String[] obj = new String[strs.size()];
        int i=0;
        for(String str : strs){
            obj[i]= (String)str;
            i++;
        }
        parameters=obj;
        }

        else{
        parameters=null;
        }
    }


    // return loaded classes of a loader

    public static Class<?>[] getLoadedClasses(final ClassLoader loader){


        final Class<?>[] classes = getLoadedClasses(loader);
        return classes;

    }

    public class MyThread extends Thread{
        Object[] actuals = { new String[] { "" }};
        public void run(){
            Method m = null;

            /*
             * Method[] m1= new Method[10]; for (Class c : loadedClasses) {
             * m1=c.getMethods(); } for(Method m2: m1){
             * System.out.println(m2.getName()); }
             */
            /* System.out.println(loadedClasses.size()); */
            for (Class<?> c : loadedClasses) {
                /*
                 * System.out.println(c.toString());
                 * System.out.println(c.getConstructors());
                 */
                // for (int i = 1; i < file.size(); i++) {
                /*
                 * for(Method meth : c.getMethods()){ meth.setAccessible(true);
                 * 
                 * }
                 */

                try {
                    if (c.getMethod("main", new Class[] { String[].class }) != null) {
                        m = c.getMethod("main", new Class[] { String[].class });
                        break;
                    } else {

                    //  System.out.println("This class does not contain main");
                        continue;
                    }

                } catch (NoSuchMethodException e) {

                    System.out.println("Program does not contain main");

                } catch (SecurityException e) {
                    e.printStackTrace();
                }

            }

            try {

                if(parameters==null){

                    //System.out.println("Invoker of" + actuals[1]);
                m.invoke(null, actuals);
                }
                else{
                    try {

                        System.out.println("It Fails Here");
                        m.invoke(null, parameters);
                    } catch (Exception e) {
                        System.out.println("Illegal arguments");
                    }
                }

                // CallStack.print();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

The problem with my executor is while executing the realestate program genetraes the following error

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at executorOfLoaderClasses.ClassExecutor$MyThread.run(ClassExecutor.java:365)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
    at edu.ncsu.realestate.gui.Main.main(Main.java:39)
    ... 5 more

I realized that while invoking the main I am passing a parameter to the main which is an object of string "" however realestate program does not take any arguments by default ,so for the time being I changed the argument passed to the method to null just to check whether it works fine now.

and again an error was generated as shown below

java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at executorOfLoaderClasses.ClassExecutor$MyThread.run(ClassExecutor.java:366)

Why is this happening the realestate program as mentioned in the http link does not take any arguments by default.

Is this way of execution buggy to other possible input programs ??

The realestate program I mentioned is working absolutely fine when run in eclipse as a Java application

The actual bug in the code from the question

The Main method you invoke expects either zero or two arguments, but you pass one.

    public static void main(String[] args) {
            GameMaster master = GameMaster.instance();
            MainWindow window = new MainWindow();
            GameBoard gameBoard = null;
            if(args.length > 0) {
                    if(args[0].equals("test")) {
                            master.setTestMode(true);
                    }
                    try {
                            Class c = Class.forName(args[1]); // <-- this is l. 39
                            gameBoard = (GameBoard)c.newInstance();
                    }

You should write

Object[] actuals = { new String[] { }};

or

Object[] actuals = { new String[0] };

in order to pass not a single empty argument, but no argument at all.

General information about argument types

If main is the startup method of a Java application, it always has signature

public static void main(String[] args)

For this reason, from the java perspective it will always be a method expecting a single argument, which is an array of strings. So on the command line, you use a variable number of arguments, but within the Java application, it is always a single array. Some developers might declare the arguments as String... args , which means that you might pass a variable number of strings in the Java application, but that is only syntactic sugar which the compiler will translate into an array creation. For reflection, you will always have to pass the array yourself, as there is no automatic array creation for variadic methods there. So always pass a single argument of type String[] via reflection.

Method.invoke takes an Object... for the arguments, so you can either pass an Object[] containing all the Java arguments, or you can pass each argument separately and have the compiler construct an Object[] from those. So it is up to you whether you pass the String[] array directly to invoke or wrap it in an Object[] as you did with your actuals .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM