I want to call a method in different class in a different package using the lines injected through javassist. Is there any other way to call those methods directly without making them public static and call using the fully qualified classname? In here it describes about a importPackage() method. But it looks like it can be used only with classpool object where we try to obtain the required class file.
Imports are compile time only. If you want to invoke non-static methods in another class, you will need some means of acquiring the correct object instances to invoke against, such as:
Instantiating them
Some sort of object finder
Implements a shared collection that can be accessed statically that contains the objects.
One of these would need to be injected into your class so you can get the instances, and then you can wire in the actual invocation.
It might be helpful if you provided some code samples, perhaps how the code is now, and how you would like it to be.
Related
We use System.out.println without instantiating it or creating object of it. Same goes to Math class and many others (I guess). Is there something special about these classes? Can we use the classes and methods declared within those classes in same fashion? Please help.
You don't have to create objects for the System and Math classes because the methods and variables in those classes are static. This means that they belong to the class itself, not to instances of the class.
For reference see:
Understanding Class Members
Beyond Basic Arithmetic
This is something called 'static' method. In order to invoke static method, you do not need to have an instance of the class.
This also has other side effects such as non-existing 'this' and thus static methods cannot invoke instance methods.
This is mostly used for some sort of utility classes which are often stateless.
Math is a good example for it.
I suggest to read a bit about static methods and static in Java in general.
You don’t need to create object of System and Math class to use it because they have static methods. Static methods belong to the class and thus doesn’t require it to be instantiated.
Although, you can create its object and then also use those methods, but creating a class for static method is of no use.
Why don't we have to create object of System or Math classes in java and use them directly?
Because the methods of Math are declared as static methods, and because System.in / System.out / System.err are static variables.
Is there something special about these classes?
No. Any variables or methods that are declared as static will behave that way.
Can we use the classes and methods declared within those classes in same fashion?
I don't really understand what you are asking there. But, if you are asking if you can create an instance of Math or System so that you can do something like this:
Math myMath = new Math();
myMath.min(1, 2);
No, you can't. Neither of those classes has a public constructor, so you can't new them.
And if you could do that, it would be really bad style!
Reference:
Understanding Class Members
First,you cannot make an instance of the class Math,because it has only a single constructor and it's been marked private and you just can't make an instance of it from outside the class.
Snapshot of the source code of the class Math
Second,you don't need to do that.All of the methods in class Math are static,just use the class name and the dot operator and you can invoke any one of them.
System class can't instantiate/create object because this System class have private constructor.
And it's all members and methods are static, that can be accessible directly by Class name.
this simple and valid answer will help you.
We don't instantiate every other class or method because the JVM(Java Virtual Machine) already loads them into the project and hence, we can use these classes again and again. One such example is the main method. These classes/methods are already predefined for us so there is no need for us to instantiate such classes/methods because they are static.
You don't have to instantiate the object in order to use methods of the math class.
Because to use this methods we don't need object. We can directly invoke this.
These type of classes are called static. Here methods can directly invoked by the class itself.
They are already defined in the JVM. We don't need to instantiate to use methods of this class.
I need to call a bunch of Class.forName() s on third-party classes but this causes the static initializers to run of all the affected classes. This running of the static initializers is a undesired side effect that I want to avoid because the logic pulls in all sorts of other dependencies and other garbage.
Is there a way to prevent these from running? I need the class object, not just info I can get by hacking the class binaries.
I am aware that classes need to be properly initialized before methods should be invoked. I am not doing anything with the code of these classes, I want them frozen.
If you are dependent on the real class containing everything the class consists of, you are stuck with the static initializers unless you patch your virtual machine.
If you just need class meta-information (e.g. method names of the class, implemented interfaces) you can go with a library like Reflections.
Your suggestion to use Powermock/Mockito to suppress the static initialization would go in a similar direction as the Reflections library. Both Test frameworks change the bytecode of classes before loading, resulting in slightly different classes than the original one.
Without using any additional libraries, you can just do:
Class.forName(className, false, this.getClass().getClassLoader());
Where the second argument is initialize , to flag whether you want the class initialising.
The class is initialized only if the initialize parameter is true and if it has not been initialized earlier.
The single argument call to forName is just a convenience wrapper:
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
See: Class.forName documentation (Oracle Java SE7)
I'm writing some kind of library. I have an abstract class there. Client-code needs to extend it to use some methods. May happens that user quits application and after he restarts it I need to restore reference to his concrette class. My idea was to save canonical name of user's class and then just make newInstance() for it. However for some reason it can't create the instance. I've made a test:
void foo(AbstractClass a) {
String classname = a.getClass().getCanonicalName();
System.out.println(classname); //Output: "com.test.clientcode.Main.ConcretteClass"
a = null; // here I lost my reference to ConcretteClass for example, so all I have is a classname
Class.forName(classname).newInstance(); //Throws exception: "java.lang.ClassNotFoundException: `com.test.clientcode.Main.ConcretteClass"
}
It's a method within library code. For argument a I give it an instance of concrette user class.
UPDATE: to make things easier: in my library I have a method like above, argument a is a reference to client's ConcretteClass as we see in the output of 2nd line. Then I lose my reference. How can I make a new instance of ConcretteClass if the only thing I know is ConcretteClass' canonical name?
Your approach won't work.
If you want to "restore" the instance you should do in other way instead of simply newInstance. this is one thing. I don't know your concrete requirement, so I cannot answer further on the "restore" part.
I said your approach won't work, because you said your are writing a "library", so I guess client code will import your class, that is, your abstract class is in client codes's classpath. however, the client class won't be in your classpath. that's why you got the classnotfound Ex.
same as if I extend a class from guava for example, how come in guava codes, it knows my class and create an instance of my class?
It is possible in plain Java to override a method of a class
programmatically at runtime (or even create a new method)?
I want to be able to do this even if I don't know the classes at compile time.
What I mean exactly by overriding at runtime:
abstract class MyClass{
public void myMethod();
}
class Overrider extends MyClass{
#Override
public void myMethod(){}
}
class Injector{
public static void myMethod(){ // STATIC !!!
// do actual stuff
}
}
// some magic code goes here
Overrider altered = doMagic(
MyClass.class, Overrider.class, Injector.class);
Now, this invocation...
altered.myMethod();
...would call Injector.myMethod() instead of Overrider.myMethod().
Injector.myMethod() is static, because, after doing "magic"
it is invoked from different class instance (it's the Overrider),
(so we prevent it from accessing local fields).
You can use something like cglib for generating code on-the-fly
In java6 has been added the possibility to transform any already loaded class. Take a look at the changes in the java.lang.instrument package
For interfaces there is java.lang.reflect.Proxy.
For classes you'll either need a third-party library or write a fair bit of code. Generally dynamically creating classes in this way is to create mocks for testing.
There is also the instrumentation API that allows modification of classes. You can also modify classes with a custom class loader or just the class files on disk.
I wrote an article for java.net about how to transparently add logging statements to a class when it is loaded by the classloader using a java agent.
It uses the Javassist library to manipulate the byte code, including using the Javassist compiler to generate extra bytecode which is then inserted in the appropriate place, and then the resulting class is provided to the classloader.
A refined version is available with the slf4j project.
If I got it right, the main problem that concerns you is how to pass a static method delegate (like in C#), through the instance interface method.
You can check this article: A Java Programmer Looks at C# Delegates (archived), which shows you how to get a reference to your static method and invoke it. You can then create a wrapper class which accepts the static method name in its constructor, and implements your base class to invoke the static method from the instance method.
I am storing a list of classes through (Classname.class) and would like to instantiate one? Is this possible?
newInstance seems to the method I am after but it doesn't support a constructor?
You can use Class.getConstructors (or Class.getConstructor) to get a list of available constructors, and invoke any of them with Constructor.newInstance, which does accept parameters.
Just to add one point I see missing:
You can invoke newInstance directly on the Class object if it has a public null constructor. (Null constructor is the constructor with no arguments.)
Otherwise, you can find constructors via Class.getConstructors() as others have said.
The Java tutorial on reflection covers this well. But yeah, basically Class.getConstructors, then Constructor.newInstance is where it's at.
Java is designed so you can never "trick" it as long as you use the java.lang/java. classes or other standard libraries. One of the most important things of OOP is that objects should be in a defined state, thus you can be safe that the constructor is always run. Even if you're using some strange-looking reflection libraries to get your work done.
So, using Class.forName("me.Test").newInstance(); (or similar) will under-the-hood invoke the Test() constructor for you.
If you want to invoke another constructor the code is something like:
Test test = (Test)Class.forName("Test").getConstructor(String.class).newInstance("Hello World");
Here the getConstructor asks what the constructor looks like (it wants a string) and then you call it with a string.
You cannot construct new classes this way.
If you have the name of a class you can use Class.forName(className) to load/reference a class.
If you have the byte code for a class you want to create you can have a class loader load the byte code and give you the class. This is likely to be more advanced than you intended.
If you have a list of Class objects obtained through class literals, you might as well statically reference the constructors rather than slipping into reflection evilness.