There is component within the application that uses com.sun.java.swing.SwingUtilities2 Now I understand that this class shouldn't be used, but it's a component within the system that uses it.
Therefore since it's no longer available in Java 6 I get a NoClassDefFoundError. How can I get around this issue without having to upgrade the component as I don't yet know if that's an option.
If you have absolutely no other choice, then you should figure out exactly what it was that the class is using from SwingUtilities2, and then make proxies for that functionality in your own SwingUtilities2. You can then stick it in your own com.sun.java.swing package, which will overlap with the original one, and if the same class loader that loads your component is also aware of SwingUtilities2, then the one will see the other and your application will work.
Depending on what the component is, and what it used out of SwingUtilities2, this could be significantly harder than upgrading it or even rewriting it.
Da-dum! This is precisely why you should pay attention to those pesky warnings admonishing you not to rely upon internals of the JVM!
Just a though, I don't know if this would work.
Try pulling out the SwingUtilities2 class and put it in a patch jar, include this jar in your classpath. Hopefully this works until you can change the source.
The only correct way (out of hacking) is to ask vendor to fix and rebuild this component to Java 6. The possible working way is copy sun.swing.SU2 to com.sun...SU2 and package it into separate jar (e.g. java6fix.jar) and try to run your application. It will be fine if you add this patch jar into jvm bootclasspath. The best patch should be to create own com.sun..SU2 and delegate all calls to sun.swing.SU2. And take a look for different version of component which support Java6 maybe also from different vendor. Also if the problem is only in the mentioned line ((Boolean)c.getClientProperty(AA_TEXT_PROPERTY_KEY)); then you may put your own client property for this component to prevent NPE. When you take this path you can just simply create your own com.sun...SU2.AA_TEXT_PROPERTY_KEY and call c.setClientProperty(AA_TEXT_PROPERTY_KEY, true) on this component. Also try to disable anti aliasing check on component if possible.
Related
I have a java class in a 3rd party lib with a private member which is assigned at class instantiation.
public class CacheLookupUtil extends AbstractCacheLookupUtil<InvocationContext> {
#Inject
private BeanManagerUtil beanManagerUtil;
private CacheKeyGenerator defaultCacheKeyGenerator = new DefaultCacheKeyGenerator();
private CacheResolverFactory defaultCacheResolverFactory = new DefaultCacheResolverFactory();
...
...
}
My problem is that the assignment of defaultCacheResolverFactory is causing an exception due to the wrong constructor having been chosen.
If I try to subclass CacheLookupUtil, this assignment is still done in the parent class, so I'm no further ahead.
Is there any mechanism I can use in Java reflection that would allow me to construct/instantiate the object, but prevent the assignment of defaultCacheResolverFactory, and allowing me to set the value via reflection?
I know this is an ugly solution, but to be honest, I cannot visualize any other way to proceed.
Is DefaultCacheResolverFactory part of your libraries jar?
If not I would guess that this is a version problem.
Otherwise you should lookout for a bugfix version of your library or open a ticket.
Last but not least you could use AspectJ Load-Time Weaving to manipulate the bytecode at class loading time. But this requires that you always start your code with Load-Time Weaving. See Load-Time Weaving.
So I personally would prefer option 1 or 2.
Check the version of library that contains CacheLookupUtil (I understand that its a thirdparty class). For example, let it be jar-A.
Then check the version of jar that contains DefaultCacheResolverFactory. If its also jar-A, this effectively means that this library doesn't work at this version, so you should upgrade.
If its in some jar-B, then check pom.xml of jar-A itself, what version of dependency on jar-B is required, probably you override the version of this jar.
Then adjust the version so that jar-A's expectations from the version of jar-B will match :)
For me its the best solution.
Now as for dirty tricks. One trick can be to create your own copy of CacheLookupUtil and put it into the same package, depending on class-loaders policy (you haven't specified in which environment do you run, so I assume plain java) it might load first and effectively "substitute" CacheLookupUtil from the jar.
Of course the same can be done with DefaultCacheResolverFactory (so that you could fix the no-op constructor there)
If you believe its a real bug, an another option to consider is to fork from the "buggy" library and create your own version of it with a fix. Of course you better make the developers of the original library to fix this bug so that eventually you could get back to the official version, in the world of open source, sometimes solutions like this work as long as the licencing permits doing so.
If it doesn't help, then Byte Code manipulation is the only way to fix as #PowerStat already mentioned. this I believe, Java Agent, class loading patching, AspectJ, and so forth. Hopefully you won't get there only because of this issue :)
Ok, here is the issue. We are using an old version of Tomcat (6.0.35) because our version of linux (ubuntu 12.04) doesn't have a repository with a newer version of it. Unfortunately, there is a bug in 6.0.35 that is affecting us ( https://issues.apache.org/bugzilla/show_bug.cgi?id=53725 ). IT doesn't want to/can't change tomcat versions. They want to use the package management system, they don't want to rebuild tomcat. They can't maintain something like this on a whole bunch of servers and we don't particularly want to disable Gzip. We can deal with the corruption until we can finally upgrade.
So with that background, the real question. The changes which fix this bug reside in one single class. We came up with a crazy solution (which will probably never see production, but was more of a "this would be so terrible, lets try it!" sort of idea), How about we compile the fixed version of the class and hotswap it in. After all, tomcat and our project use the same JVM.
Is this doable/possible/more than a little crazy?
Some hurdles. We are using Java 6. The new class adds methods and fields. I'm not sure that tomcat keeps it around.
In most cases this is unreasonable to actually do. The only way to cleanly unload a class and then load a replacement is to let the ClassLoader used to load that particular class be garbage collected. This will require you to remove all references to any of the classes that ClassLoader loads (which is probably at least all of TomCat) and reload them using a ClassLoader that loads all classes like normal, except for the class you 'fixed'. You would have to make it so that it loads that class instead of the old one, while still allowing the other classes to load normally.
In short, it is possible, however it will require digging into java ClassLoaders. I'd recommend that you do not actually attempt this, as it will be very annoying to get right and it will certainly not work without shutting down the TomCat server first (since you have to reload all of TomCat's classes).
Who is doing the unzipping, Tomcat or the application? If its the application, just make a copy of the class in error to the root of your project classpath in src/main/java and put there the patched version of the class.
Upon packaging the patched class will be in WEB-INF/classes, and override the version in the server. But its overridden only from the point of view of the application, the server cannot see the patched version and still sees the buggy version.
If its tomcat itself that needs to unzip something, then its not possible to fix that without tinkering with the server.
But if its the application doing the unzipping its for sure possible, there is no obligation to use the libraries of the server we can use our own more updated copies, usually not in patches but in jars in WEB-INF/lib - the server is designed for that.
I want to change an application by changing a component. In Java, it would seem that the swappable object could be placed in a jar. One version of the jar could be deleted and another identically named jar would be put in its place.
Is this the best practice for swappable Java components, and if not, then what?
Edit: to be clear, the mooted organization is to have a jar with the constant objects, and a separate jar with the swappable object. Runtime swappability is neither expected nor sought. Remote installation and runtime swapping is probably more sophisticated than necessary for my needs.
You should really look at Dependency Injection for this kind of use case(either Spring or CDI).
Also you could consider OSGi
Have a look at OSGI
Applications or components can be remotely installed, started, stopped, updated, and uninstalled without requiring a reboot;
I'm looking for a neat way to override a class from the bootstrap class path, rt.jar.
The reason is OpenJDK7 bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7104625
The fix for this bug is a trivial (see linked mailing list post) change to sun.awt.X11.XComponentPeer. So I was wondering if there is an easy way to override just this one affected class on my classpath, without having to repack/rebuild rt.jar (so the fix isn't lost on the next automatic update of OpenJDK).
Ideally, it would also affect Eclipse...
I assume that java -Djava.system.class.loader=myClassLoader would work? Is there any other way to override a single class with such a "hotfix"? (Note: not used in my own code, but deep in Java AWT code)
You can use the VM parameter -Xbootclasspath/p to prepend your own JAR file with the patched class to the boot class path.
I believe the only supported way of doing this is to "patch" rt.jar by replacing the desired *.class file. 7-Zip can help you easily do this.
This is exactly how Oracle supplied their double-parsing bug fix with their FPUpdater tool, which was essentially a script that did just this. (Some history.)
I think you can try to use javaagent
You must intercept event, when JVM loads system class and swap it to yours
I think #ziesemer is correct, but you may be able to use the classloader to replace the offending class when your app is bootstrapping. This may be cleaner if you don't want to worry about the JDK updating underneath you, though you'd have to stick this bootstrapping classloader code into every app you are working on.
I'm in the midst of converting a legacy app to Spring. As part of the transition, we're converting our service classes from an "instantiate new ones whenever you need one" style to a Springleton style, so I need a way to make sure they don't have any state.
I'm comfortable on the *nix command-line, and I have access to IntelliJ (this strikes me as a good fit for Structural Search and Replace, if I could figure out how to use it), and I could track down an Eclipse install, if that would help. I just want to make absolutely sure I've found all the possible problems.
UPDATE: Sorry for the confusion. I don't have a problem finding places where the old constructor was being called. What I'm looking for is a "bullet-proof" why to search all 100+ service classes for any sort of internal state. The most obvious one I could think of (and the only one I've really found so far) is cases where we use memoization in the classes, so they have instance variables that get initialized internally instead of via Spring. This means that when the same Springleton gets used for different requests, data can leak between them.
Thanks.
In Eclipse you can just right click on a variable/type and there is an option for References (or Declarations) -> (Workspace / Project / Hierarchy) which can help you find all instances of it neatly.
I would suggest using Eclipse's built in refactoring tool, it will do its best to change every instance associated to the class accordingly. I would go a step further and rename the class of that you want to change so, at worst case, a full compile would fail and you can easily fix any of those issues.