Class Redefine not working - byte-buddy

SO I am trying to redefine a class. I have a class named folder. In OSGi (using Felix) I have a new Folder class with the same methods but some additional logging.
I am trying to take the Folder Class from Felix and redefine the main Folder class on the main classloader
I do have the agent set on startup.
new ByteBuddy()
.redefine(Class.forName(classToOverride.trim()), ClassFileLocator.ForClassLoader.of(felixClassLoader))
.name(classToOverride.trim())
.make() .load(contextClassLoader);
I have tried different strategies in the load method.
Without any strategies I get the following error
Caused by: java.lang.IllegalStateException: Cannot inject already loaded type: class com.dotmarketing.portlets.folders.model.Folder
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.inject(ClassInjector.java:187) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:187) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:120) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:79) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4376) ~[byte-buddy-1.6.12.jar:?]
at com.dotmarketing.osgi.GenericBundleActivator.publishBundleServices(GenericBundleActivator.java:177) ~[dotcms_4.1.0_563a5c3.jar:?]
With ClassReloadingStrategy.fromInstalledAgent I get no error but doesn't work.

On a JVM, you cannot simply redefine an already loaded class. You can only redefine a class using a Java agent where Byte Buddy supplies the AgentBuilder API which you can use. Note that it is only possible to change the content of methods but not a class's layout. You probably want to have a look at the Advice API to do so.

Related

Why ClassGraph finds classes from other deployment on Wildfly?

I prepared WAR archive and I deployed it on Wildfly 21.
I want to find all classes annotated with javax.ws.rs.ApplicationPath annotation.
try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages( PACKAGE ).scan())
{
final ClassInfoList classesWithAnnotation =
scanResult.getClassesWithAnnotation( ApplicationPath.class.getName() );
}
It finds two classes, one from my deployment and one from other deployment. I undeployed other deployment to make sure that one class is taken from it and I am sure, if only one deployment is deployed on Wildfly then it return only one class.
I do not understand why ClassGraph finds classes from other deployment. How to configure ClassGraph to scan only deployment which ClassGraph itself belongs? I guess that I have to configure class loader, but I do not know how to do it correctly.
Unfortunately it seems that there is no any configuration options that could meet my requirements. Source code modification is needed.
There is JBossClassLoaderHandler#findClasspathOrder method.
First org.jboss.modules.Module is retrieved from class loader. Next getCallerModuleLoader method is invoked and returns different class loader. Original class loader is an instance of org.jboss.modules.ModuleClassLoader class. Class loader retrieved by getCallerModuleLoader method is an instance of org.jboss.as.server.moduleservice.ServiceModuleLoader class. Next moduleMap method is invoked and returns map of modules. This map contains both my deployments. Next operations are executed for each map entry.
I also do not see possibility to add my own implementation of nonapi.io.github.classgraph.classloaderhandler.ClassLoaderHandler without source code modification because handlers are kept in unmodifiable final filed in ClassLoaderHandlerRegistry class.

Class sharing between byte-buddy interceptors/advices

I am trying to pass monitoring/tracing information through all my external calls in my java application.
To make it transparent, I'm trying to use byte-buddy but have some troubles getting it to work.
To trace every incoming (http) request, I intercept HttpServlet.service(), extract the token header from the HttpServletRequest and put it in a static ThreadLocal in a class named TokenHolder.
To trace every outgoing (http) request, I intercept HttpURLConnection and add the token header I get from the same ThreadLocal (TokenHolder).
The problem I have is that TokenHolder seems to be initialized twice and my 2 interceptors are not writing-to/reading-from the same ThreadLocal and I can't find a way to do it.
I suppose the problem is that HttpURLConnection lives in the bootclasspath while the servlet API does not.
Bonus question: is it possible to intercept URL.openConnection()? That was my first idea but I never could do it because I suppose the URL class is loaded before the agent (because of URLClassLoader) but I don't know if there are workarounds to that.
Yes, you can register a RedefinitionStrategy where Byte Buddy transforms previously loaded classes. To do so, you do however need to avoid adding methods or fields. This can typically be done by using Advice only.
You are also right that classes need to live on the bootstrap loader. You can inject classes into the bootstrap loader by placing them in a jar and using the designated method in the Instrumentation interface.

createCache fails in non-static method

I am creating a cache with a CacheStoreFactory implementation and a CacheStoreSessionListener. If I set the CacheConfiguration with these fields and then call createCache but in an INSTANCE method I get this exception:
Exception in thread "main" javax.cache.CacheException: class
org.apache.ignite.IgniteCheckedException: Failed to validate cache
configuration (make sure all objects in cache configuration are
serializable): LongCache
In a static method, this does not occur. This can be easily reproduced by modifying the CacheJdbcStoreExample.java in examples. This is happening under Ignite 1.30
Most likely you declared the factory or the listener as an anonymous class. Anonymous classes always contain reference to the parent class (LongCache in your case). So if the factory is serialized in the context of LongCache instance, this instance is also serialized. In case of static method this instance doesn't exist, therefore everything works.
I would recommend to convert anonymous classes to private static classes. This will give you more control on what is serialized.

Sencha Touch: perform read (load) operation from singleton model

I have a singleton model and an associated AJAX proxy.
If I make a call to MyModel.load(), I get the error:
MyModel.load is not a function
However, you do have load in Model:
http://docs.sencha.com/touch/2.4/2.4.1-apidocs/#!/api/Ext.data.Model-static-method-load
On the contrary, MyModel.save() exists and I can access it.
Is this a bug or am I missing something?
The load method listed on Ext.data.Model is a static method on the class definition, not an instance. The documentation even denotes this is a static method. When you want to load a record, you don't load an already instantiated record, you load the model definition and that loading creates an instance.
The save method listed on Ext.data.Model is an instance method, the docs do not denote this as a static method. You don't save a class definition, you save an instance.
Example usage: https://fiddle.sencha.com/#fiddle/lvj

User / Application specific values in Twisted .tac file

What's the best practice for putting additional configuration items, specific to my application, in a twistd ".tac" file? How do I access these items from inside my class?
Is there some property in the "application" object that's intended to store these?
Create your own twisted.application.service.IService implementation (by subclassing twisted.application.service.Service or just by implementing the correct methods and attributes on a class all of your own). Give this class an __init__ that accepts the application-specific parameters. Launch the rest of your application logic in the startService method that is automatically called when twistd starts the reactor (for all IService objects attached to application). Use the objects you passed to __init__ in startService to get your application going in the right direction.
For example, see the FingerService defined in one of the Twisted tutorials (but unlike that tutorial, don't define all your classes in the .tac file! define them in modules and import them into the .tac file).