Hi all, 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.
views:
59answers:
4An 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/
Have you considered using AspectJ? You could set a pointcut on URL constructors and thus be notified of any new URL instance creation.
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.
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.