views:

126

answers:

5

Hi all,

My goal is:

Third class will read the name of the class as String from console.Upon reading the name of the class, it will automatically and dynamically (!) generate that class and call its writeout method. If that class is not read from input, it will not be initialized.

And I am taking java.lang.IllegalAccessException: Class deneme.class3 can not access a member of class java.lang.Object with modifiers "protected" error. And ı don't know how ı can fix it.. Can anyone help me?

import java.io.*;

import java.lang.reflect.*;


 class class3
{

    public void run()
      {
        try
        {    
            BufferedReader reader= new BufferedReader(new InputStreamReader(System.in)); 

              String line=reader.readLine();

              Class c1 = Class.forName("java.lang.String");
              Object obj = new Object();
              Class c2 = obj.getClass();

              Method writeout = null; 
              for( Method mth : c2.getDeclaredMethods() ) {                  
                     writeout = mth; 
                     break;                  
              } 
              Object o = c2.newInstance(); 
              writeout.invoke( o );              

        }
        catch(Exception ee)
        {
       System.out.println("ERROR! "+ee);
        }

        }

  public void writeout3()
  {
      System.out.println("class3");
  }
      }

class class4
{
  public void writeout4()
  {
    System.out.println("class4");
  }
}

class ornek {


    public static void main(String[] args) {
       System.out.println("Please Enter Name of Class : ");
       class3 example = new class3();
       example.run();               
    }
}
+2  A: 

what function are you trying to execute exactly? looks to me like you are just picking the first method without actually checking what it is. try to pick a specific method which is public.

Omry
A: 

Looks like it will it will try to call the first method of Object. Seems to have picked up clone. That will require setAccessible(true). There are probably other problems with your code.

Tom Hawtin - tackline
A: 

The above seems very confused to me. In no order:

  1. you're not using the name of the class entered on standard input
  2. you're loading a class via forName(), but it's not the one you specify in 1. above
  3. you should find the writeout() method of that class using getDeclaredMethods() or similar.

In short, I think you have all the required methods/APIs you need to load a class that someone specifies on the command line, instantiate an instance, and then call a method. It's just that at the moment your class loading/method location isn't doing the above.

Brian Agnew
+1  A: 

It's not clear what you are doing in your code.

It seems like, first you declare c1 that is java.lang.String without using it.. then you load a new java.lang.Object, go through its declared methods and you choose the first one found as writeout and you try to invoke it without ever knowing what you are calling.

To do what you tried to explain I suggest you to:

Define an interface like Invokable with a method that you want to call dynamically, for example

interface Invokable {
  public void invokeMe();
}

Then whenever you generate a new class by loading the name you can cast it to your interface and call that method without going crazy:

Class<?> class = Class.forName("your.YourClass");
Object target = class.newInstance();

if (target instanceof Invokable)
 ((Invokable)target).invokeMe();

(of course YourClass will have to implement the Invokable interface)

This approach clearly defines what the program will be able to instantiate dynamically and what you are supposed to be allowed to do with these objects without worrying about searching for methods or allow strange things to happen..

Jack
+1 for interface suggestion.
polygenelubricants
+1  A: 

This is the most glaring problem with your code:

Method writeout = null; 
for( Method mth : c2.getDeclaredMethods() ) {                  
   writeout = mth; 
   break;                  
} 

You're just grabbing the first declared method of c2, which is Object.class. Who knows what the method is? (in my case it's protected void java.lang.Object.finalize() throws java.lang.Throwable, by the way).

Another problem is earlier:

String line=reader.readLine();
// presumably you're reading the name of the class to find here...

Class c1 = Class.forName("java.lang.String");
// why do you need String.class? what is c1 used for?

Object obj = new Object();
Class c2 = obj.getClass();
// so now c2 is Object.class? what are you trying to accomplish?

Presumably you may want to do this instead:

  1. Read the name of the class to find
  2. Find that class using Class.forName
  3. Reflect on that class to find the writeout* method

That means something like this:

String line = reader.readLine();

Class<?> writeoutClass = Class.forName(line);

Method writeout = null;
for (Method mth : writeoutClass.getDeclaredMethods()) {
    if (mth.getName().startsWith("writeout")) {
        writeout = mth;
        break;
    }
}

Object o = writeoutClass.newInstance();
writeout.invoke(o);

This will print "class3" and "class4" depending on the class name you type in. You'd need to make it more robust, but it illustrates the idea.


It should be mentioned that if possible, you should make these dynamically created type implements SomeInterface (see Jack's answer). Also read Effective Java 2nd Edition, Item 53: Prefer interfaces to reflection.

polygenelubricants
but when I am using "Class<?> writeoutClass = Class.forName(line)" instead of "Class c1 = Class.forName("java.lang.String")" , am taking java.lang.ClassNotFoundException
rubby
Well, what did you type in? If you type in garbage name, then of course that class couldn't be found!!! You have to type in the _fully qualified_ name of the class that you want to find. Are `class3` and `class4` in a package? Called `deneme` perhaps?
polygenelubricants
Take an easy, please...But ı don't know how ı can write "fully qualified" name of the class which ı want to find it.Of course class3 and class4 in my package..
rubby
If you don't know the name of the class that you want to find, then you can't find it by name (i.e. what `Class.forName` is for). There is no `package` declaration in the code in your question, but the error message mentions "`Class deneme.class3`", so I assume the code is actually in `package deneme;`. In that case, try typing in `deneme.class3` and `deneme.class4`.
polygenelubricants
yeah you understand what ı want to do:1.Read the name of the class to find2.Find that class using Class.forName3.Reflect on that class to find the writeout* methodthat is it..now i will try deneme.class3 and deneme.class4 , and i will back you..And also thank you very much for understanding me..
rubby
ı'am taking the same error java.lang.ClassNotFoundException:
rubby
//edited for typo// Add this line `System.out.println(class3.class.getName());` as the first line in your `main` function and tell me what it prints.
polygenelubricants
when ı wrote System.out.println(class4.class.getName()); ı took :java.lang.ClassNotFoundException: demmmmdeneme.class4
rubby
Put `System.out.println("My name is " + class3.class.getName());` before `example.run();` in your code and run it. I want to know what that line prints.
polygenelubricants
output is that :My name is deneme.class3
rubby
Then if you type in exactly `deneme.class3` you should be able to find it. Try adding `System.out.println("[" + line + "]");` before the `...Class.forName` line.
polygenelubricants
it gaves me[mmmmm]ERROR! java.lang.ClassNotFoundException: mmmmm
rubby
Did you type in `mmmmm`??? I'm sorry, but if you did then I'm not sure what's the best way to help you any more.
polygenelubricants
no ı wrote on console mmmmm, thanks for helping, ı am very grateful to you..
rubby
My original question is:There will be two different classes with the Writeout method, class3 and class4printing out their own name. Third class will read the name of the class as String from console .Upon reading the name of the class, it will automatically and dynamically (!) generate that classand call its writeout method. If that class is not read from input, it will not be initialized.ı want to do that...
rubby
"automatically and dynamically (!) generate that class" -- nothing in the code as of now suggests quite an advanced capability like this. How and where are you doing that part?
polygenelubricants