Can Javassist change a static final field?
Hi,
I'm using ClassFile.renameClass as in jbossretro in order to replace instances of a class in a some.jar to my own class.
This is what I wants to achieve:
Some classes in the some.jar are using class A:
public class A {
....
}
I've created a new class AA:
public class AA extends A{
....(overwrite some methods)
}
I want to replace the A instances with AA in the some.jar.
In the some.jar I have class B as follows:
public class B {
....
private final A a = ....;
....
}
But...
I cannot replace the final fields.
Hi,
I'm using ClassFile.renameClass as in jbossretro in order to replace instances of a class in a some.jar to my own class.
This is what I wants to achieve:
Some classes in the some.jar are using class A:
public class A {
....
}
I've created a new class AA:
public class AA extends A{
....(overwrite some methods)
}
I want to replace the A instances with AA in the some.jar.
In the some.jar I have class B as follows:
public class B {
....
private final A a = ....;
....
}
But...
I cannot replace the final fields.
I've looked at JBossRetro - it's a tool to set bytecode compiled with java 1.5 as it was compiled with java 1.4 - when they replacing the StringBuilder with JBossStringBuilder (their own implementation)- they have the same bug. final field referring to StringBuilder are not replaceable.
Are you familiar with thoses frameworks? Is there a way to replace the final declaration - I'm working on the bytecode.
10x,
Keren
javassist - www.jboss.org/javassist
jbossretro - www.jboss.org/community/docs/DOC-10738

Comments
if class B is the only one, why not replace it also? (through class path or class loading)
if not, but you can replace the class loader, then maybe asm / cglib will be helpful to rewrite the class after loading but before returning it to the jvm.
and of course you can always rewrite it while it is still in the jar.
I'm trying to manipulate an applet product - with minimum code replacement - Java agent is not an option.
I want to 'touch' class B as less as possible...
I drop the question on jboss forums (jbossretro and javassist) and it looks like it's javassist bug:
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4222587#4222587
I'll be more then happy - if someone from Tikal will help me a and take the challenge of fixing it and drop it to javassist.....
They opened a bug at jira (declared as major):
https://jira.jboss.org/jira/browse/JASSIST-77
Keren
I think Ittay's suggestion is a good one. Why limit yourself to using only JbossRetro, when you know there is a bug associated with it?
If the change in the Applet.jar is constant (and correct me if I am wrong) , why not replace all instances of Class A with your Class AA in the Jar itself before it is loaded by the class loader, instead of extending it as you did? This way you can re-distribute the Applet Jar without the need to use byte code instrumentation.
tell me how
this is the case - I need to translate an HP product that didn't use (or partially use) I18N.
I have the sources and the binaries and can use both if I want.
One important thing - my intervention should be as minimum as possible.
we tried use aspectj - but there is no way to interrupt in the middle of a method. and there are methods that are creating a full ui.....
we figured out that the best and easy way is to 'catch' the UI components (JLabel, JTextField etc..) and replace the 'setText' methods (ctors with text and other text involved methods as well).
again - I cannot override the rt.jar - not all customers will like that...
Then I ran into JBossRetro - and 'stole' the rename classes option like in StringBuilder
This can be a great solution for me - I'm running post compile (at the moment) and this is an easy to use solution - and it works like a charm.
The problem is - when the product declare:
final JLabel label = new JLabel(sometext);
the JLabel is switch to be MyJLabel (I can see that on the bytecode) but the final field on the Local variable table: (again in the byte code) is still referring to JLabel
if i understand correctly, you have a class com.hp.Foo that you want to changes somewhat and have all of the other classes use the modified Foo, right?
one crude option is then to take Foo.java, copy it to a new project, change, create a jar and put that jar before the original jar. that way the modified Foo is loaded.
this is crude because you copy the whole file. so you can create a patch instead and apply it before building.
no - I have no Foo class that I want to load
I want to 'replace' the UI components instances (like swing.JLabel) in the product (every place someone is using it - with be manipulated). The UI components are placed in the rt.jar and I dont want to deal with that.
I created a MYJlabel that extends JLabel, pack it in a jar and add that jar as thirdparty
1-If you have the source com.hp.A , why not add I18N support using resource bundles directly in the A Class source code? would that be interpreted as too much intervention?
This way, the code should be backward compatible.
2-The option of replacing rt.jar is not realistic, since the rt.jar is on the clients computer where the Applet is loading. While the applet loads from a server, rt.jar is loaded from the JRE on the clients computer and you wouldn't replace all the clients rt.jar files.
As far as I know, you wouldn't be able to modify the class loader on the client since as you mentioned it is an Applet. You can only add a new Jar in the HTML page that loads the applet and hence to achieve the same result as if you changed the class-loader, i.e:
codebase="http://keren.hp.com/java/lib"
archive="HP.jar" width="100" height="100">
The manifest for HP.jar is:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.2
Created-By: 1.4.2_06-b03 (Sun Microsystems Inc.)
Class-Path: Keren-HP.jar
The code didn't turn Ok in the previous post:
applet code="A.class"
codebase="http://keren.hp.com/java/lib"
archive="HP.jar" width="100" height="100">
The manifest for HP.jar is:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.2
Created-By: 1.4.2_06-b03 (Sun Microsystems Inc.)
Class-Path: Keren-HP.jar