How to use an anonymous class instance in another generate bytecode class - java

I have difficulty in using a generated bytecode class which is loaded by Unsafe.defineAnonymousClass(). I am wondering how to use an object of anonymous class to initiliaze another class (or anonymous class).
Take an example class Callee below for example, its constructor accepts Callee2 as parameter.
Class Callee{
Callee2 _call2;
public Callee(Callee2 callee2){
...
}
}
During runtime, I generated new classes for both Callee2 and Callee, and both new classes are loaded by Unsafe.defineAnonymousClass(). For new Callee, the constructor is also changed to be:
public test.code.jit.asm.simple.Callee(test.code.jit.asm.simple.Callee2.1506553666);
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=2
0: aload_0
1: invokespecial #65 // Method java/lang/Object."<init>":()V
....
8: return
while the generated class name of Callee2 is:
class test.code.jit.asm.simple.Callee2/1506553666
I created an instance of `Callee2/1506553666' and want to create instance of new Callee with it, but fail:
newCls.getConstructor(args).newInstance(objs);
where
args = [class test.code.jit.asm.simple.Callee2/1506553666]
and
objs= [test.code.jit.asm.simple.Callee2/1506553666#39b0a038]
The args[0] is meanless as this class is loaded by anonymous loader (Anonymous classes are not referenced by any class loaders). So it really puzzles me how to pass objects in objs array to a method invocation..
The exception occurs on the invocation of getConstructor (args) with message:
java.lang.NoClassDefFoundError: test/code/jit/asm/simple/Callee2/1506553666
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2483)
at java.lang.Class.getConstructor0(Class.java:2793)
at java.lang.Class.getConstructor(Class.java:1708)
at code.jit.asm.util.ReflectionUtil.adapt2GeneratedObject(ReflectionUtil.java:36)
at code.jit.asm.services.BytecodeGenerator.generator(BytecodeGenerator.java:164)
The exception is clearly for me since the anonymous class is transient to any classloader. But in my case, I do need initialize the new Callee (also anonymous class) by new Callee2 instance (The bytecodes in Callee's constructor will reads Callee2's field members), so is there any workaround to pass new callee2 instance for the new callee's constructor?

Have a look at the signature and documentation comment, which is not available in the standard API documentation as it’s not part of the official API:
Define a class but do not make it known to the class loader or system dictionary.
For each CP entry, the corresponding CP patch must either be null or have the a format that matches its tag:
Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
Utf8: a string (must have suitable syntax if used as signature or name)
Class: any java.lang.Class object
String: any object (not just a java.lang.String)
InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments
… (params:)
cpPatches where non-null entries exist, they replace corresponding CP entries in data
public native Class<?> defineAnonymousClass(
Class<?> hostClass, byte[] data, Object[] cpPatches);
In other words, you may provide an array of the same size as the constant pool of the class you’re going to define. Keep nulls where you don’t want to modify it. Right at the places where your constant pool has a CONSTANT_Class_info representing an anonymous class, you simply pass the associated Class object in the array. So there’s no lookup for the class then, you don’t even have to provide the correct class name in the class bytes.
There are some obvious limitations:
Problem will arise if you have circular dependencies as you need an already existing Class object to patch the pool of another class. Well, for class uses that are known to be resolved lazily, it might work
You can only patch CONSTANT_Class_info to a Class which is sufficient for, e.g. accessing members of that class or creating new instances of it. But it doesn’t help when an anonymous class is part of a signature, i.e. you want to declare a field of that type or use a method having it as parameter or return type. But you may access such methods using the option of patching a CONSTANT_InterfaceMethodref_info entry via a MethodHandle (ahem, once implemented as I guess “NYI” means “not yet implemented”)…

Related

How are constructors accessed?

I've never understood why we're able to call constructors for a class from other classes. A constructor is a method, and normally when trying to call a method from a class, we'd have to either make that method static so we can access it as
MyClass.method();
or we'd make an instance of that class and then call that method (now obviously this method would contradict the premise of this question)
MyClass myClass = new MyClass();
myClass.method();
But in the case of a constructor we do neither. How does Java call the constructor of a class without doing either of these methods? I know that a constructor for a class must be visible to the class you're invoking it from, i.e if the class constructor you're invoking is in a different package, you have to import that package.
So how does Java handle invoking constructors with respect to being able to invoke them without using the methods above?
Class constructors have special support in the Java language and Java bytecode beyond that given to normal methods. In particular, they get the special name <init> and are invoked using a different bytecode instruction (invokespecial as opposed to invokevirtual which is used for your typical method-call-with-runtime-dispatch that normal method calls look like).
Quoting from JVMS (JVM spec) section 3.8:
Java Virtual Machine class instances are created using the Java Virtual Machine's new instruction. Recall that at the level of the Java Virtual Machine, a constructor appears as a method with the compiler-supplied name <init>. This specially named method is known as the instance initialization method (§2.9). Multiple instance initialization methods, corresponding to multiple constructors, may exist for a given class. Once the class instance has been created and its instance variables, including those of the class and all of its superclasses, have been initialized to their default values, an instance initialization method of the new class instance is invoked. For example:
Object create() {
return new Object();
}
compiles to:
Method java.lang.Object create()
0 new #1 // Class java.lang.Object
3 dup
4 invokespecial #4 // Method java.lang.Object.<init>()V
7 areturn
As you can see, the reference compiler that was used to generate this sample first creates an uninitialized instance of the object in question, pushes it on the stack along with any constructor parameters (not shown), and uses invokespecial to invoke the appropriate constructor to initialize the object. At the language level, Java will not let you write code that exposes the completely uninitialized object before the constructor is invoked, although you can still leak a partially constructed object.
It's worth noting that there are unsafe means (literally in a hidden-away class called Unsafe) to obtain a reference to an object that is initialized at a low level but whose constructor is never called. These somewhat break out of the Java language spec, and should only be used with extreme care where absolutely needed.

Is it possible to define my own String class?

Is it possible to define my own String class which has the exact same name as java.lang.String? My assumption is that after I have defined it, I can use it directly or load it with a class loader.
Sorry, the code I wrote has a mistake. The String class of the parameter String[] args of the method main() was incorrectly referenced to my own defined String. That is why it occured a compile error.
My working result is that we can define a class named String in my own namespace or java.lang. But since JVM has loaded the default java.lang.String, we can't load our own String and use it.
Yes, you can define that class, but you won't be able to use it. The class java.lang.String will be loaded out of the JRE at bootstrap, and you can't reload a class in the bootstrap classloader. If you try to use your own classloader, the JVM will notice that java.lang.String is already loaded and just use that one.
From the JLS section on class loading:
Given the same name, a good class loader should always return the same class object. (This means that the java.lang.String class that gets pulled in a bootstrap will be the authoritative class.)
If a class loader L1 (the bootstrap loader) delegates loading of a class C to another loader L2 (your own loader), then for any type T (java.lang.String) that occurs as the direct superclass or a direct superinterface of C, or as the type of a field in C, or as the type of a formal parameter of a method or constructor in C, or as a return type of a method in C, L1 and L2 should return the same Class object. (Your own java.lang.String would be conflicting with all of the parameters and fields in anything else loaded by the bootstrap loader and would cause virtually anything past the loading of your rogue class to come crashing down with link or cast errors.)
What exactly are you trying to do, anyhow? java.lang.String has very strictly defined semantics, and changing its behavior at all would break an enormous amount of code.

Does a Java constructor return the Object reference?

I know Java's constructors can't have any type and interestingly it cannot even be void. A logical explanation for that would be that a constructor returns the initialized object's reference.
MyClass myObject = new MyClass();
The constructor of myClass will now return the object reference after instantiating it and save it in the object variable MyObject and that's why the constructor can't have a return type.
Is that right? Could someone confirm this?
No, actually, the constructors are compiled into the class file like methods having the name <init> and a void return type. You can see these "<init>" invocations in stack traces. The expression new Type() is compiled as an instruction new which just creates the instance of Type and an additional method invokation (invokespecial) to one of the constructors declared in Type.
The verifier will ensure that such a special method is invoked at exactly once on a newly created instance and that it is called before any other use of the object.
It’s just a programming language design decision to let constructors have no return type from the Java language point of view. After all, new Type(…) is an expression that evaluates to the newly created instance of Type and you can’t get a return value from the constructor with that programming language construct. Further, if you add a return type, Java will unconditionally assume that it is a method, even if it has the same name as the class.
That’s simply how it was defined: (It makes parsing the class definition easier)
The SimpleTypeName in the ConstructorDeclarator must be the simple name of the class that contains the constructor declaration, or a compile-time error occurs.
In all other respects, a constructor declaration looks just like a method declaration that has no result (§8.4.5).
I suppose you could say that constructors have a "special syntax" used specifically for returning instances of the desired object. You do not specify the return type in these cases. The new keyword is used together with the constructor method to produce an instance of the class type.
If you'd like to control the return type of an instance generation method, then you should probably be looking at using a type of factory design pattern, wherein a static method creates an instance (using a constructor), and then returns a more explicit type (say for example, the super type, or an interface type).
This pattern is good when you'd like to decide which type to return based on some parameter, but leave the actual type hidden to the consumer of the instance generation method.
A constructor is not a methed. It does not return anything. It is used for initialization purposes, especially useful when those initializations depend on parameters or there is a chance that exceptions will be thrown (though both are optional).
So, unlike a method, it is not inherited and does not have a return type (not even void).
The idea is that you are "constructing" an instance of MyClass by calling the constructor itself. The idea of the constructor is to instantiate and not to return. Having created myObject you can then refer to public methods and variables part of its declaration which will provide you with the required data being returned as an answer to a call. It is important to understand that the constructor does not return anything it simply creates an instance which can then be used to refer to methods and variables (which return data) declared within the instantiated class.

what is the Class object (java.lang.Class)?

The Java documentation for Class says:
Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
What are these Class objects? Are they the same as objects instantiated from a class by calling new?
Also, for example object.getClass().getName() how can everything be typecasted to superclass Class, even if I don't inherit from java.lang.Class?
Nothing gets typecasted to Class. Every Object in Java belongs to a certain class. That's why the Object class, which is inherited by all other classes, defines the getClass() method.
getClass(), or the class-literal - Foo.class return a Class object, which contains some metadata about the class:
name
package
methods
fields
constructors
annotations
and some useful methods like casting and various checks (isAbstract(), isPrimitive(), etc). the javadoc shows exactly what information you can obtain about a class.
So, for example, if a method of yours is given an object, and you want to process it in case it is annotated with the #Processable annotation, then:
public void process(Object obj) {
if (obj.getClass().isAnnotationPresent(Processable.class)) {
// process somehow;
}
}
In this example, you obtain the metadata about the class of the given object (whatever it is), and check if it has a given annotation. Many of the methods on a Class instance are called "reflective operations", or simply "reflection. Read here about reflection, why and when it is used.
Note also that Class object represents enums and intefaces along with classes in a running Java application, and have the respective metadata.
To summarize - each object in java has (belongs to) a class, and has a respective Class object, which contains metadata about it, that is accessible at runtime.
A Class object is sort of a meta object describing the class of an object. It is used mostly with the reflection capabilities of Java. You can think of it like a "blueprint" of the actual class. E.g. you have a class Car like this:
public class Car {
public String brand;
}
You can then construct a Class object which describes your "Car" class.
Class myCarClass = Class.forName("Car");
Now you can do all sorts of querying on your Car class on that Class object:
myCarClass.getName() - returns "Car"
myCarClass.getDeclaredField("brand") - returns a Field object describing the "brand" field
and so on. Every java object has a method getClass() which returns the Class object describing the Class of the Java object. So you could do something like:
Car myCar = new Car();
Class myCarClass = myCar.getClass();
This also works for objects you don't know, e.g objects you get from the outside:
public void tellMeWhatThisObjectsClassIs(Object obj) {
System.out.println(obj.getClass().getName());
}
You could feed this method any java object and it will print the actual class of the object you have given to it.
When working with Java, most of the time you don't need to worry about Class objects. They have some handy use cases though. E.g. they allow you to programmatically instanciate objects of a certain class, which is used often for object serialization and deserialization (e.g. converting Java Objects back and forth to/from XML or JSON).
Class myCarClass = Class.forName("Car");
Car myCar = myCarClass.newInstance(); // is roughly equivalent to = new Car();
You could also use it to find out all declared fields or methods of your class etc, which is very useful in certain cases. So e.g. if your method gets handed an unknown object and you need to know more about it, like if it imlements some interface etc, the Class class is your friend here.
So long story short, the Class, Field, Method, etc. classes which are in the java.lang.reflect package allow you to analyze your defined classes, methods, fields, create new instances of them, call methods all kinds of other stuff and they allow you to do this dynamically at runtime.
getClass() is a method that returns an object that is an instance of java.lang.Class... there is no casting involved. Casting would look like this:
Class<?> type = (Class<?>) object;
I would also like to add to ColinD 's answer that getClass will return the same object for instances of same type. This will print true:
MyOtherClass foo = new MyOtherClass();
MyOtherClass bar = new MyOtherClass();
System.out.println(foo.getClass()==bar.getClass());
Note that it is not equals, I am using ==.
In order to fully understand the class object, let go back in and understand we get the class object in the first place. You see, every .java file you create, when you compile that .java file, the jvm will creates a .class file, this file contains all the information about the class, namely:
Fully qualified name of the class
Parent of class
Method information
Variable fields
Constructor
Modifier information
Constant pool
The list you see above is what you typically see in a typical class. Now, up to this point, your .java file and .class file exists on your hard-disk, when you actually need to use the class i.e. executing code in main() method, the jvm will use that .class file in your hard drive and load it into one of 5 memory areas in jvm, which is the method area, immediately after loading the .class file into the method area, the jvm will use that information and a Class object that represents that class that exists in the heap memory area.
Here is the top level view,
.java --compile--> .class -->when you execute your script--> .class loads into method area --jvm creates class object from method area--> a class object is born
With a class object, you are obtain information such as class name, and method names, everything about the class.
Also to keep in mind, there shall only be one class object for every class you use in the script.
Hope this makes sense
A Class object is an instance of Class (java.lang.Class). Below quote taken from javadoc of class should answer your question
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
The Object class is the parent class of all the classes in java by default. In other words, it is the topmost class of java.
The Object class is beneficial if you want to refer any object whose type you don't know. Notice that parent class reference variable can refer the child class object, know as upcasting.
Let's take an example, there is getObject() method that returns an object but it can be of any type like Employee,Student etc, we can use Object class reference to refer that object. For example:
Object obj=getObject();//we don't know what object will be returned from this method

Classes not extending java.lang.Object

While you create a user defined class in Java, you do not specify it as extending Object. But still the class is an Object. How does this work? How does javac or the JVM inject all properties of a class to the user defined class?
If you don't actually write extends Object, the compiler inserts it for you.
EDIT: Apparently I caused some confusion about whether there is actually an insertion of code going on. I wasn't entirely sure myself so I ran a little experiment: create the following class in file test.java:
public class test {}
and compile it, then run
javap -c test
to disassemble the bytecode. Look what comes out:
Compiled from "test.java"
public class test extends java.lang.Object{
public test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
}
So yes, the compiler does actually insert extends java.lang.Object (or the bytecode equivalent) into the class.
All java classes implicitly extend java.lang.Object. From the documentation:
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
Here's a link to JVM spec as well:
The standard class Object is the superclass (§2.8.3) of all other classes. A variable of type Object can hold a reference to any object, whether it is an instance of a class or an array. All class and array types inherit the methods of class Object.
Well, this may be a glib answer (my favorite kind), but it probably does it the same way it derives a class if you specify a parent. Isn't that how you'd do it if you were writing the compiler?
It's because all user defined types implicitly inherit from Object.
To say that the JVM "injects" properties or methods into the class makes it sound like it's something the compiler or runtime does after the fact, as though the .class file is different. Really, all that happens is that when the parser sees that you haven't included any base class with extends, it simply pretends you explicitly specified Object. From that point onward, the compiler treats it the same as if you'd typed it out yourself, and the JVM hasn't a clue what you did or didn't specify in the source code.

Categories

Resources