It seems like everybody has had an unpleasant brush with the Java Service Provider, that thing you can do with a file named like META-INF/services/com.example.Interface, but that nobody uses except for trying to load the right XML parser. I'm trying to work with a library that uses the Service Provider API, and trick it so that I can provide some runtime-extended classes (using cglib) that don't actually implement the interface but can be made to do so easily.
Basically, I think the steps I need to perform are:
Create a custom class loader that will respond to getResources(...) and return an "extra" URL
Also have that class loader hook getResourceAsStream(...) to return a list of the classes I am going to manipulate with cglib, when asked for the "extra" resource
Finally, have that class loader load those classes when requested
But here's where I get lost. For example, when the library tries to determine what implementers are out there, it calls getResources(...) which returns a bunch of URLs. But getResourceAsStream(...) doesn't take URLs, it takes "names". Names which seem to be classpath-relative, and therefore the same everywhere. So META-INF/services/com.example.Interface in has the same "name" as META-INF/services/com.example.Interface in their JAR, right? Except somehow this works with those blasted XML parsers...
Of course, all of this assumes they were smart/kind enough to call ClassLoader.getSystemClassLoader() rather than using ClassLoader.getSystemResources(...), ClassLoader.getSystemResourceAsStream(...), etc., as in the latter case there's no way to hook the ClassLoader and provide the faked file.
I guess in that case I could use BCEL to manipulate the class files when my code is being packaged by Maven, rather than waiting until runtime to do it with cglib?
The idea I described was along the right track. The mistake I made was in thinking that using ClassLoader.getResourceAsStream(..) to access the contents of the URLs. Instead, you should just URL.openStream().
Had I found it before posting, java.util.ServiceLoader (#since 1.6) provides some insight into how to do things correctly.
Related
So my problem is very simple, I got a plugin management program that allows plugins to be loaded and run AFTER the initial program got launched. All that works fine, I can load and unload the classes as I wish but the problem I encountered now is the following:
I am now trying to write a plugin to that plugin management system which is going to take care of all networking to prevent every plugin to host its own connection. The problem is that I can't use bootstrap classes as the plugins are loaded dynamically on runtime (I don't even know if it's there till I look for it and load it) yet I do still want to override the normal socket class to filter what's going on. Same goes for other classes that I want to override using plugins so that other plugins trying to use those classes and their functions will no longer be able to access the native implementation but instead will have to go through my implementation of it. Don't ask, I have reasons :P
So all just put together shortly: I need a way to dynamically on runtime override native classes with my own implementations of them so that everything else I load will use my implementation instead of the native one. Any ideas?
Depending on how the dynamic class loading works, this is probably not possible (you need to provide more details to be sure, but if it's using a new ClassLoader per plugin, you can't override system classes from it)
But for your specific problem, namely to provide your own implementation of network sockets, there is a much better solution.
You need to implement java.net.SocketImplFactory and call Socket.setSocketImplFactory, as well as ServerSocket.setSocketFactory with an instance of your factory. (Don't ask me why these two methods are not named the same)
Your factory should then create your subclass of SocketImpl that can do all networking in its own way.
You should not override Socket. Just use Socket.setSocketFactory to provide your own implementation.
I don't want to use the URL Classloader to load classes.
I want to implement this myself.
I don't want to use a solution like JRebel (although it's great).
I've got prior experience of JavaAssist, bytecode generation, implementing javaagent class transformers etc.
I would like to write a javaagent which hooks into the classloader or defines it's own system classloader.
I'll store the class files in an in memory cache, and for particular files, periodically reload them from disk.
I'd prefer to do this in a way which doesn't involve continuously polling the file system and manually invalidating specific classes. I'd much rather intercept class loading events.
I last messed around with this stuff 4 years ago, and I'm sure, although my memory may deceive me that it was possible to do, but 8 hours of searching google doesn't present an obvious solution beyond building a patched JVM.
Is this actually possible?
I've created a stub implementation at https://github.com/packetops/poc_agent if anyone's interested in a simple example of javaagent use.
update
Just found this post - I may have been using the wrong approach, I'll investigate further.
It depends on what you want to do. If you want to reload your classes and define new ones, then you are fine with implementing your own classloader, as you already found.
If you want to replace existing classes, things become more "envolved". You can do this by implementing your own tiny Java agent. See the Java documentation, how to do this: http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html
With the instrumentation mechanism you can not freely redefine classes, quote from Instrumentation.redefineClass:
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.
If you want to do more, you need to load it again. This can be done under the same name, by using a different classloader. The previous class definition will be unloaded, if no one else is using it any more. So, you need to reload any class that uses your previous class also. Utlimatly, you end up reinventing something like OSGi. Take a look at: Unloading classes in java?
The title speaks for itself. The language is Java.
Yes, there is. This is however a tedious and expensive work. You need to crawl through all class files and all JAR files with help of ClassLoader#getResources() and a shot of java.io.File and load all classes of it with help of Class#forName() and finally check if the method is there by Class#getMethod().
However, there are 3rd party API's which can take the tedious work from hands, but it is still expensive, because loading a class would cause its static initializers being executed.
A cleaner way is to make use of annotations and annotate the methods in question and then make use of libraries which searches for classes/methods/fields based on the annotations, such as Google Reflections.
On the other hand, if the entire package name or the JAR file name is known beforehand, then the work will be less tedious and expensive (no need to do stuff recursively nor to load the all of the classes of entire classpath).
Update: I remember, I ever wrote sample code to achieve something like that, you can find it here. It's good to start with, you only need to change it a bit to check the method.
No, you can't, in general. If you could get a complete list of available classes you could check each of them using reflection - but you can't ask a classloader for a list of everything that's available. (For instance, it may be fetching classes over HTTP, and may not know all the files available.)
If you knew that you were interested in classes in a jar file, however, you could open the jar file, find all the class files within it and ask the classloader for those classes. It would be somewhat fiddly.
What's the bigger picture here? There may be a better way to approach the problem.
Also, in Eclipse, you can simply ask for this :
Clic on the method, and type Ctrl-T.
I'd like to implement a dynamic plugin feature in a Java application. Ideally:
The application would define an interface Plugin with a method like getCapabilities().
A plugin would be a JAR pluginX.jar containing a class PluginXImpl implementing Plugin (and maybe some others).
The user would put pluginX.jar in a special directory or set a configuration parameter pointing to it. The user should not necessarily have to include pluginX.jar in their classpath.
The application would find PluginXImpl (maybe via the JAR manifest, maybe by reflection) and add it to a registry.
The client could get an instance of PluginXImpl, e.g., by invoking a method like getPluginWithCapabilities("X"). The user should not necessarily have to know the name of the plugin.
I've got a sense I should be able to do this with peaberry, but I can't make any sense of the documentation. I've invested some time in learning Guice, so my preferred answer would not be "use Spring Dynamic Modules."
Can anybody give me a simple idea of how to go about doing this using Guice/peaberry, OSGi, or just plain Java?
This is actually quite easy using plain Java means:
Since you don't want the user to configure the classpath before starting the application, I would first create a URLClassLoader with an array of URLs to the files in your plugin directory. Use File.listFiles to find all plugin jars and then File.toURI().toURL() to get a URL to each file. You should pass the system classloader (ClassLoader.getSystemClassLoader()) as a parent to your URLClassLoader.
If the plugin jars contain a configuration file in META-INF/services as described in the API documentation for java.util.ServiceLoader, you can now use ServiceLoader.load(Plugin.class, myUrlClassLoader) to obatin a service loader for your Plugin interface and call iterator() on it to get instances of all configured Plugin implementations.
You still have to provide your own wrapper around this to filter plugin capabilites, but that shouldn't be too much trouble, I suppose.
OSGI would be fine if you want to replace the plugins during runtime i.g. for bugfixes in a 24/7 environment. I played a while with OSGI but it took too much time, because it wasn't a requirement, and you need a plan b if you remove a bundle.
My humble solution then was, providing a properties files with the class names of plugin descriptor classes and let the server call them to register (including quering their capabilities).
This is obvious suboptimal but I can't wait to read the accepted answer.
Any chance you can leverage the Service Provider Interface?
The best way to implement plug-ins with Guice is with Multibindings. The linked page goes into detail on how to use multibindings to host plugins.
Apologize if you know this, but check out the forName method of Class. It is used at least in JDBC to dynamically load the DBMS-specific driver classes runtime by class name.
Then I guess it would not be difficult to enumerate all class/jar files in a directory, load each of them, and define an interface for a static method getCapabilities() (or any name you choose) that returns their capabilities/description in whatever terms and format that makes sense for your system.
I am working on a big (lots of classes) java project and I have it's source code but most of the classes are dynamically created or downloaded via ClassLoaders.
Anyways, I'd like to be able to "override" the java.net.URL class so I could trace down the calls to open a url. I can not use a sniffer because the content is SSL encrypted.
I tried to extend the java.net.URL but it didn't work because its a final class.
I also opened the source to java.net.URL and modified it and could successfully build it, now how can I make the default java classloader to load my modified copy of java.net.URL instead of the original one?
Any suggestions are welcome! Thanks in advance.
An option would be to use AspectJ and weave your extension code into the URL class instead of extending it. That way you don't have to modify any of the original sources and you can still "extend" a final class. The downside of course is, that you add another dependency to your project.
If you have not yet worked with AOP, you may find a short introduction to AOP at my blog: http://whatiscomingtomyhead.wordpress.com/2010/02/06/aspect-oriented-programming-an-introduction/
You can't extent URL, as you have discovered. You may be able to get the JVM to load your custom version of the class, but IMHO that sounds like a nightmare.
Thankfully you can implement a custom URLStreamHandlerFactory and register it by URL.setURLStreamHandlerFactory(). This will allow you to wrap and monitor when URLs open streams, just as you desire.
EDIT
But you won't be able to use this approach if your app already registers one; URLStreamHandlerFactories are 1/app. And many types of app containers use one (e.g. Tomcat), so if you're using one of those you're SOL.
Have you considered using AspectJ? You could set a pointcut on URL constructors and thus be notified of any new URL instance creation.
If you have modified classes in the standard API, you have to prepend the boot class path with your classes (jars or directories), otherwise the VM internal classes will have priority over any classes added to the normal class path. With Sun's VM, you can use the argument -Xbootclasspath/p: to add new classes with a higher priority than the internal implementations.
Another option, without modifying the URL implementation may be to implement a ProxySelector. Opening a URLConnection would cause the URL implementation to query ProxySelector.select(URI uri) for a suitable proxy for the given address. This will even work if you actually are using proxies. You can obtain the system ProxySelector with ProxySelector.getDefault() before you register your own implementation and delegate the select calls to the original implementation after you've tracked the URI, which is passed to the select method.