The issue: We generate classes using ByteBuddy, load them and at one point will need to add/remove fields without re-starting the application.
If I understand correctly, in Java it is not possible to modify the schema (add fields/methods) of a class already loaded into a class loader.
My question: As a workaround, would it be a possible/reasonable to create a new class loader when a such a conflict occurs - load all generated classes into the new class loader and close the old class loader?
Thank you.
There is a VM version of OpenJDK that supports such transformations, the Dynamic Code Evolution VM.
For a regular VM, you can load a class in a new class loader. However, in this case no previous instance will be an instance of this altered class. You would need to recreate all instances. If this is feasible for you, this is an option.
Related
In Tapestry(5.0) when ever I try to recompile my changes in java class i get a popup saying
Hot Swap Failed
abc.xyz : hierarchy changes not implemented
abc.xyz : Operation not supported by the VM
AFAIK this should be working and because of this I end up restarting the debug session which takes quite a bit of time.
Any help with this ?
You see this warning, because IntelliJ is failing to hot swap the classes, because, as the message says: VM doesn't support this operation for your changes.
What Tapestry is doing is actually not a hot swap, it's called "Live Class Reloading".
In short: instead of updating existing classes and objects inside VM (what hot swap is doing), Tapestry throws old classes away with all their state, and loads/initialises them again using a custom class loader. It can only do this for its managed classes: page/component/mixin classes and IoC service implementations that are registered using service interface. Everything else can only be reloaded with a hot swap if it's implemented by a VM.
You can read more details about Live Class Reloading in official documentation .
I have the following code working in a SpringBoot application, and it does what's I'm expecting.
TypePool typePool = TypePool.Default.ofClassPath();
ByteBuddyAgent.install();
new ByteBuddy()
.rebase(typePool.describe("com.foo.Bar").resolve(), ClassFileLocator.ForClassLoader.ofClassPath())
.implement(typePool.describe("com.foo.SomeInterface").resolve())
.make()
.load(ClassLoader.getSystemClassLoader());
Its makes is so that the class com.foo.Bar implements the interface com.foo.SomeInterface (which has a default implementation)
I would like to . use the above code by referring to the class as Bar.class, not using the string representation of the name. But if I do that I get the following exception.
java.lang.UnsupportedOperationException: class redefinition failed: attempted to change superclass or interfaces
I believe due to the fact that it cause the class to be loaded, prior to the redefinition. I'm just now learning to use ByteBuddy.
I want to avoid some reflection at runtime, by adding the interface and an implementation using ByteBuddy. I've some other code that checks for this interface.
This is impossible, not because of Byte Buddy but no tool is allowed to do this on a regular VM. (There is the so-called dynamic code evolution VM which is capable of that).
If you want to avoid the problem, use redefine rather then rebase. Whenever you instrument a method, you do now however replace the original.
If this is not acceptable, have a look at the Advice class which you can use by the .visit-API to wrap logic around your original code without replacing it.
I am currently experiencing a problem in my RCP application and wanted to ask, if someone stumbled over the same problem and can give me some valuable hints:
My RCP application allows plugins to provide implementations of a specific abstract class of my model (singleton) to extend my model during runtime via the update manager. I instantiate these classes via
extensionPointImplementation.createExecutableExtension(..)
after parsing the Eclipse registry. I can serialize the created instances using the default Java serialization API.
Now to the problem: The plugin trying to deserialize the objects cannot find the class implementations of the model extensions due to the fact, that there is no plugin dependency between the plugins. Nevertheless, it is not possible for me to create such a dependency which would make the idea of extending the model during runtime obsolete.
Is it possible to solve this problem by using the default Java serialization API or do I have to implement my own serialization (which parses the Eclipse registry and creates the instances via the line shown above if all necessary plugins are available, otherwise throw an exception) which might be based on the default Java serialization API (if possible I do not want to create the serialization completely by myself)?
Thanks.
You need to define a so called buddy policy.
In the bundle trying to instantiate the class add
Eclipse-BuddyPolicy: registered
to the manifest.mf.
In the bundle providing the class add
Eclipse-RegisterBuddy: <symbolic name of the bundle instantiating the class>
to the manifest.mf.
I'm learning about ClassLoading concepts in java.
I know that can get the System classLoader with ClassLoader.getSystemClassLoader() method using java.lang.ClassLoader class. Is it possible to get Extension class loader also?
I'm aware that JVM loads the BootStrapClassLoader and we cannot instantiate it. But what about Extension class loader?
Thanks in Advance.
You can try this one sun.net.spi.nameservice.dns.DNSNameService.getClassLoader(). DNSNameService is one the class that exist as the Extension class loader.
Another option is to write something like this:
ClassLoader cl =new Object(){}.getClass().getEnclosingClass().getClassLoader();
ClassLoader prev = null;
while(cl!=null){
prev=cl;
cl=cl.getParent();
}
System.out.println(prev);
prev will contain reference to extension class loader.
Note: You can write besides
new Object(){}.getClass().getEnclosingClass().getClassLoader() idiom Thread.currentThread().getContextClassLoader() or even simpler YourClassName.class.getClassLoader() While these idioms are not identical any of them will do the job.
See http://www.javacodegeeks.com/2011/03/understanding-extending-java.html for some more details.
My VB project is large enough that it requires several files. It was originally developed as a Console App and I created each file as a MODULE. All modules could use subroutines, data structures and constants from other MODULES and everything worked fine. I needed to add basic windowing to the app and this required that the app be converted from a Console App to a Windows Forms App. The main window is Form1 which is not a MODULE but a CLASS. The problem is that some MODULE based functions cannot access subroutines, data and constants that are defined within the CLASS Form1 unless they are incorporated into the CLASS file and this makes the CLASS file very large. If I add a new Class file to the project, it also cannot interoperate with Class Form1 in the same way that multi-MODULE code interoperates.
How does one spread CLASS code across several files and still allow it to interoperate as if it were in a single file? Alternatively, how does one create several CLASS files that operate the way multiple MODULE files operate.
I am sure that there are all kinds of best practices that I am violating but the goal to to get some prototype software working and interfaced to some lab equipment.
Thank you in advance
Use a partial class (Partial keyword on the class declaration). Each partial "bit" of the class will be merged at compile time. All partial bits must be in the same project.
Modules are default shared and do not require initialization with the New keyword. When you made your console app a windows app, it became a class...You could change it to the same behavior as a module simply by making it a Public shared Class and making all properties and methods inside shared as well.
so while you can access your methods and properties in your modules without initialization, you would need to use the NEW method to initialize your Class methods.
To access the Class from the module you would simply have to use:
SomeModulemethod
dim x as new CLASS
CLASS.SOMEMETHOD
someModuleMethod End
You could also use Partial Classing to split up your Classes, but it is much better to decide if you really need a separate class for what you want to do.