Byte Buddy instantiate class without parameters for constructor - java

I am trying to instantiate a class that doesn't have an empty parameter constructor (and it's direct parent also doesn't have an empty parameter constructor)
Class<?> newClass = new ByteBuddy();
.subclass(BufferedImage.class)
...
.make()
.load(BufferedImage.class.getClassLoader())
.getLoaded();
BufferedImage bufferedImage = dynamicTypeBufferedImage.getConstructor().newInstance();
I am wondering if this is possible using byte buddy. Currently I am getting an error saying that the getConstructor() of the proxy class is not found which makes sense because the empty parameter constructor doesn't exist. Is there a way to define the empty parameter constructor such that this instantiation works?
I have tried:
...
.constructor(any()).intercept(to(new Object() {
public void construct() throws Exception {
System.out.println("CALLING XTOR");
}
}).andThen(SuperMethodCall.INSTANCE)) // This makes the difference!
...
which came from here and gave me the error of Image class doesn't have super() (which is the parent class of BufferedImage).
I also tried:
...
.defineConstructor(Visibility.PUBLIC)
.intercept(MethodCall
.invoke(superClass.getDeclaredConstructor())
.onSuper())
...
which came from here
Lastly, I also tried the .subclass(type, ConstructorStrategy.Default.IMITATE_SUPER_CLASS); way to imitate super class but this doesn't seem to add an empty parameter constructor.
This functionality that I want, mimics the way cglib instantiates its objects using the enhancer. I know from what I have been reading that byte buddy is supposed to let the user decide how to instantiate. I was wondering if there was an easy way to just set the default instantiation to the empty parameter constructor since I don't care about setting fields in the class but rather just want to control the method space?

It is not legal to define a Java constructor that does not invoke its super constructor in some way (either directly or via another constructor), since it cannot be expressed in byte code, it cannot be done in Byte Buddy.
What you can do is:
Not define a constructor alltogether using ConstructorStrategy.Default.NO_CONSTRUCTORS.
Use a library like Objenesis to instantiate a class.
Note however that Objenesis is using unsafe API that might not be supported in a future Java version.

Related

What is the actual use of the default constructor in java?

I have read in many sources and books that constructor is used to initialise the fields when an object is created. I have also read that JVM provides a default constructor if I don't mention one. What is the purpose of a constructor if it is not required to initialise the fields like the one I have mentioned below?
I also understand that a constructor without parameter is required as
it is necessary during object creation when an argument is not passed
(when programmer-defined constructors with parameters exists).
Is it necessary for JVM to provide a constructor which is actually not required?
public class test {
int a;
public test() {
//this constructor is useless
}
public static void main(String[] args)
{
test ob= new test();
System.out.println(ob.a);
//this prints 0 which means a constructor is not required in intialising `a`
}
}
A constructor like test() makes sense if the programmer defines it since there could be other constructors which takes argument.
But why is it necessary for JVM to provide one when no constructor is declared by the programmer?
I have already tested and proved that initialising a field doesn't require constructor.
Also what does the default constructor look like?
The problem is that while you know the default constructor doesn't do anything in this example, in future the constructor might do something even if you don't realise it is and you might not be able to re-compile everywhere the code is used reliably. So the safest, simplest thing to do is to always call a constructor which might change in the future and let the JIT optimise away the constructor if it doesn't actually do anything.
The byte code always calls a contructor, whether you provide one or not. When you compile code which uses the default constructor it cannot assume the constructor doesn't do anything useful as you can add something to it later to do something useful. e.g.
Say you change
public class Test {
int a;
// public Test() { //this constructor does nothing
}
to
public class Test {
int a;
final List<String> strings = new ArrayList<>();
// public Test() { //this constructor does something now.
}
or
public class ServerTest {
final List<String> strings = new ArrayList<>();
}
public class Test extends SuperTest {
int a;
// the default constructor has to call super();
}
The constructor now initialised the strings field. You can change this class without having to re-compile everywhere it is used and say, hey, my constructor now does something useful, you should call it now.
The reason the JVM adds a default constructor if you haven't provided one is down to inheritance. Say for example you have 3 classes (A, B & C) in which B extends A and C extends B. Now when you instantiate C it will call the constructor of C and also the constructors of B and A. If a constructor was missing in one or more of these classes then the instantiation would fail. So having the compiler automatically add a default constructor avoids error like this. You may not need to actually do any work in your constructor, but it's required for the JVM to instantiate the object.
The constructor(s) (both default and custom one(s)) is not only used to initialize the fields of an object but also to initialize the object itself even if it has no fields at all. Calling the constructor, JVM allocates memory for this object and creates its reference.
It is the compiler, and not JVM, who inserts a default constructor on absence.
A default constructor is needed because the constructor of the base class needs to be called from a constructor.
The default constructor looks like:
public Test() {
super();
}
Here while you are creating the object new test(),
here parenthesis states the default constructor of object test.After creating the object,if you didnot give any constructor the default constructor is constructed by jvm.so after construction of your object first call goes to your default constructor.
The default constructor is a no argument constructor called automatically by the compiler when you haven't defined any constructor. Anyway, a constructor as the one you defined, can be also called a default constructor.
It basically calls the superclass' constructor making use of the super() method.
So the default constructor called automatically would be something like:
public ClassName(){
super();
}
Java's Compiler creates a Default Constructor if no other constructor is defined for the class.
But why?
The compiler's job is to chain the Subclass's constructor to the Super Class(ultimately Object class). It's not the Compiler's work to give a default constructor to your class therefore Java is doing it for you.
To do the chaining, it first checks if there is any constructor in the class, if yes it will add super() to that constructor.
If there is no constructor idefined in the class in order for the compiler to do a proper chaining, Java adds a default constructor and a call to super() into it.
Why ?
Because every class is a subclass of an Object class (directly or indirectly), it will inherit an object class, to do so the said Object class must be fully initialised. This is done by the default constructor.

Calling a function that does not exist via reflection/javassist

i need to call a function - (getters and setters of a property), but my problem is, the name of the property is generated at runtime (name of some variable + number).
Is it possible to manipulate the bytecode via javassist or gclib so that the function calls are directed to some proxy object/function, and there the real method name and the number extracted from the called function name, so that i can call the function afterwards (with the number as parameter)?
I tried the following, but it didnt work:
MethodHandler handler = new MethodHandler() {
#Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) {
String realMethodName=thisMethod.substring(0,5);
Integer param=Integer.parseInt(thisMethod.substring(5));
Method m = self.getClass().getMethod(realMethodName);
m.invoke(self,param);
return null;
}
};
I think this might be one of the few scenarios where using Java reflection Proxy objects might come in handy.
You could define some interface, but delegate the method to the (dynamic) invocation handler which would then call those "getter/setter" methods.
Side note: when implementing such an invocation handler you have to understand that ANY method call on the corresponding object will trigger its "invoke" method; event when you call toString or equals or whatever else is inherited from Object.
EDIT: and one more (different) thought: are you sure you need to create dynamic method names at all? If you have some numeric (or string based) key - what not using a Map for example?
Like
Map<WhateverKeyType,YourPropertyClass>
that would be much more "normal java" way of handling your problem (instead of thinking about reflection or byte code manipulation).
If you wanted to implement something similar but could think of using another library than javassist, consider using Byte Buddy (which I wrote, for disclosure).
Considering, you have an interface
interface Foo { Object getProperty() }
that you wanted to implement to access a property of the bean
class Bar { Object getAbc123() { ... } }
Then using Byte Buddy, you could implement a class
Foo accessor = new ByteBuddy()
.subclass(Foo.class)
.method(named("getProperty"))
.intercept(MethodCall.invoke(Bar.class.getDeclaredMethod("getAbc123"))
.on(new Bar()))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded()
.newInstance();
of the interface that redirects the invocation of getProperty to the method of your choosing. With a little bit of customization, you can surely create a more generic solution.

Byte Buddy causes IncompatibleClassChangeError

I use Byte Buddy (v0.5.2) to dynamically create a "subclass" of an interface (actually, I want to create a class that implements that interface). All methods invoked on an instance of this class should be redirected to another (interceptor) class.
I used the following code (with "TestInterface" being an interface that declares exactly one method "sayHello"):
final Interceptor interceptor = new Interceptor();
Class<?> clazz = new ByteBuddy()
.subclass(TestInterface.class)
.method(any()).intercept(MethodDelegation.to(interceptor))
.make()
.load(TestInterface.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
TestInterface instance = (TestInterface) clazz.newInstance();
instance.sayHello();
The interceptor class looks like this:
public class Interceptor {
public Object intercept(#Origin MethodHandle method, #AllArguments Object[] args) throws Throwable {
...
}
}
However, when I try to call the "sayHello" method (last line of my code example), I get an "IncompatibleClassChangeError". The stack trace is as follows:
Exception in thread "main" java.lang.IllegalAccessError: no such method: byteuddytest.TestInterface.sayHello()void/invokeVirtual
at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:448)
at bytebuddytest.TestInterface$ByteBuddy$0E9xusGs.sayHello(Unknown Source)
at bytebuddytest.Main.main(Main.java:32)
Caused by: java.lang.IncompatibleClassChangeError: Found interface bytebuddytest.TestInterface, but class was expected
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:965)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1387)
at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1732)
at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:442)
... 2 more
The problem seems to be related to the use of the "MethodHandle" parameter in my interceptor method. When I change the type to "Method", everything works fine. But according to the docs, "MethodHandle" should be preferred to "Method" because of performance reasons.
Is the error caused by a bug in Byte Buddy, or should I actually use a "Method" parameter in this case?
Use a Method parameter and enable caching. That should solve most of your performance issues, if you have any in the first place.
See javadoc for #Origin:
public abstract boolean cacheMethod
If this value is set to true and the annotated parameter is a Method type, the value that is assigned to this parameter is cached in a static field. Otherwise, the instance is looked up from its defining Class on every invocation of the intercepted method.
Method look-ups are normally cached by its defining Class what makes a repeated look-up of a method little expensive. However, because Method instances are mutable by their AccessibleObject contact, any looked-up instance needs to be copied by its defining Class before exposing it. This can cause performance deficits when a method is for example called repeatedly in a loop. By enabling the method cache, this performance penalty can be avoided by caching a single Method instance for any intercepted method as a static field in the instrumented type.
See the answer of Jeor which is totally correct (you should mark it as accepted). Just two remarks that do not fit into a comment:
You should of course only use a MethodHandle instead of a Method if the former allows you what you do. Invoking MethodHandles implies some JVM magic. Handles are resolved with a polymorphic signature by a JVM, i.e. their arguments must not be boxed as the JVM will simply replace the call site with a method call. In your case, this does therefore not work. The advantage of a method handle is however that it can be stored in the constant pool of a class. It is a native concept that can be accessed by a byte code instruction. Compared to that, a Method reference needs to be produced explicitly.
You should therefore rather cache the Method instance (which is mutable!). Also, note that you are currently also intercepting the methods of Object. You can clean up your code a bit by:
Class<? extends TestInterface> clazz = new ByteBuddy()
.subclass(TestInterface.class)
.method(isDeclaredBy(TestInterface.class))
.intercept(MethodDelegation.to(interceptor))
.make()
.load(TestInterface.class.getClassLoader(),
ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
TestInterface instance = clazz.newInstance();

Java - Invoking class methods

I'm following a java tutorial, i find this piece of code:
//load the AppTest at runtime
Class cls = Class.forName("com.mkyong.reflection.AppTest");
Object obj = cls.newInstance();
//call the printIt method
Method method = cls.getDeclaredMethod("printIt", noparams);
method.invoke(obj, null);
My question is: if i don't know the class type, is not much easier (and faster) try to cast the object instead of invoking methods in that way?
Why (and when) i should use this way?
Read this question
What is reflection and why is it useful?
It says:
"For example, say you have an object of an unknown type in Java, and you would like
to call a 'doSomething' method on it if one exists. Java's static typing system
isn't really designed to support this unless the object conforms to a known
interface, but using reflection, your code can look at the object and find out if
it has a method called 'doSomething' and then call it if you want to."
You can find a good tutotial here http://tutorials.jenkov.com/java-reflection/index.html
One reason of doing it this way, not sure if in your case:
Method method = cls.getDeclaredMethod("printIt", noparams);
method.invoke(obj, null);
will allow u to call printIt even if it is private.
But if you cast to your class object then u will not be able to call private methods.
If i don't know the class type, is not much easier (and faster) try to cast the object instead of invoking methods in that way?
Why (and when) i should use this way?
I assume you mean "If I know" not "If I don't know" above.
If you have com.mkyong.reflection.AppTest at compile-time, then you wouldn't need to use reflection to use it at all. Just use it:
// In your imports section (although you don't *have* to do this,
// it's normal practice to avoid typing com.mkyong.reflection.AppTest
// everywhere you use it)
import com.mkyong.reflection.AppTest;
// ...and then later in a method...
//load the AppTest at runtime
AppTest obj = new AppTest();
//call the printIt method
obj.printIt();
If you don't know the class at compile-time, you can't cast the result of newInstance to it, because...you don't have it at compile time.
A common middle ground is interfaces. If com.mkyong.reflection.AppTest implements an interface (say, TheInterface), then you could do this:
//load the AppTest at runtime
Class cls = Class.forName("com.mkyong.reflection.AppTest");
TheInterface obj = (TheInterface)cls.newInstance();
//call the printIt method
obj.printIt();
At compile-time, all you need is the interface, not the implementing class. You can load the implementing class at runtime. This is a fairly common pattern for plugins (like, say, JDBC implementations).

Invoking dynamic Method without known Constructor?

If I do this in Java to call a method name from a class dynamically, it works.
MainApp app = new MainApp();
Method meth = app.getClass().getMethod("myMethod", MyParameterType.class);
//call method
meth.invoke(app, new MyParameterType("hello"));
But this worked because I know the constructor in the invoke method. But if I were to pass the Method object as a parameter to some other classes, and I don't know who is the constructor, I cannot invoke the method any more. Even if I know, I may not want to create a different object to just make a call to the method. For eg:
//This is in the class call MainApp.java.
//There is a method in MainApp.java that looks this way: myMethod(MyParameterType param);
MainApp app = new MainApp();
OtherClass myClass = new OtherClass();
Method meth = app.getClass().getMethod("myMethod", MyParameterType.class);
myClass.callMe(meth);
//Inside OtherClass.java
public void callMe(Method meth) {
//call method
meth.invoke(########, new MyParameterType("hello"));
}
In this case, what should I put for the ######## parameter? Within the context of OtherClass.java, the base constructor object wouldn't be known. And why would I need if since meth is already a Method type that I just call like a function?
Thanks
Assuming it's an instance method, you've got to have an instance to call the method on, just like anything else. How you get hold of that instance will depend on what you're trying to do; you could pass in a Constructor, or a reference to an existing object, or some interface which will create the instance when you ask it to... we can't really give you any advice on which approach is the most suitable without knowing what you're trying to do.
If it's a static method, you can pass null for the first argument.
What it seems you are looking for or thinking about is the concept of `lambda functions``. Those can be called in isolation.
A Method type is not a standalone method, but more like a 'path' into an object. Compare this with a relative URL like /subscribe.html. Out of context this is pretty useless, but when bundled with a site like www.example.com it makes sense.
As such, Method can only be used in combination with an instance. (edit: as John mentioned, unless it's a static method of course which do not need instances)
If you can safely invoke a method without providing an instance, it should be a static method, in which case any instance provided is ignored, you can give it null.
If you have to provide an instance of the object, there is no way around this.
If the developer who write the method has labelled it non-static incorrectly, I suggest you discuss with them why they did it.

Categories