699 lines
24 KiB
HTML
699 lines
24 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
|
<html>
|
||
|
<head>
|
||
|
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||
|
<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
|
||
|
<meta content="en" http-equiv="Content-Language">
|
||
|
<title>ASM - ASM FAQ</title>
|
||
|
<meta name="Description" content="ASM is a very small and very fast Java bytecode manipulation framework.">
|
||
|
<meta name="Keywords" content="ASM,bytecode,manipulation,Java,open,source,free,software,BSD">
|
||
|
<meta name="Reply-to" content="webmaster@objectweb.org">
|
||
|
<meta name="Owner" content="ObjectWeb">
|
||
|
<meta name="Robots" content="index, follow">
|
||
|
<meta content="asm-team" name="author">
|
||
|
<meta content="asm-team@objectweb.org" name="email">
|
||
|
<script src="../js/objectweb.js" type="text/javascript"></script>
|
||
|
<link type="text/css" href="../common.css" rel="stylesheet" id="stylesheet">
|
||
|
<link type="image/x-icon" href="../images/favicon.ico" rel="icon">
|
||
|
<link type="image/x-icon" href="../images/favicon.ico" rel="shortcut icon">
|
||
|
</head>
|
||
|
<body marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" onload="MM_preloadImages('../images/menu/boutonok2.gif','../images/menu/boutonsearch2.gif','../images/menu/boutonprint2.gif','../images/menu/boutonsubscribe2.gif')" bgcolor="#FFFFFF" class="bodyproject">
|
||
|
<table cellpadding="0" cellspacing="0" width="100%" border="0">
|
||
|
<tr>
|
||
|
<td valign="top" width="245"><img alt=" " height="20" src="../images/pix.gif"></td><td width="100%" bgcolor="#E8EAF0" valign="bottom"> <a class="barre" href="http://consortium.objectweb.org/"> Consortium </a> <a class="barre" href="http://solutions.objectweb.org/"> Solutions </a> <a class="barre" href="http://middleware.objectweb.org/"> Middleware </a> <a class="barre" href="http://forge.objectweb.org/"> Forge </a> <a class="barre" href="http://myobjectweb.objectweb.org/"> MyObjectWeb </a></td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td valign="top" width="245"><a href="http://www.objectweb.org/"><img alt="ObjectWeb Consortium" border="0" height="80" width="245" src="../images/logoow.gif"></a></td><td valign="top">
|
||
|
<table cellpadding="0" cellspacing="0" width="100%" border="0">
|
||
|
<tr>
|
||
|
<td valign="top"><img alt=" " height="20" width="395" src="../images/pix.gif"></td><td valign="top" width="150"><img alt=" " height="20" width="150" src="../images/pix.gif"></td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td valign="top">
|
||
|
<table cellpadding="5" cellspacing="0" border="0">
|
||
|
<tr>
|
||
|
<td valign="top"></td><td valign="top"></td><td valign="top"></td><td valign="top"></td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
</td><td style="line-height: 20px;" valign="top" width="150">
|
||
|
<form action="">
|
||
|
<table>
|
||
|
<tr>
|
||
|
<td><select onChange="MM_goToURL('parent',this.options[this.selectedIndex].value);return document.MM_returnValue" name="navigation"><option>Go to ObjectWeb...</option><option value="http://www.objectweb.org/">Home Page</option><option value="http://consortium.objectweb.org/">Consortium</option><option value="http://solutions.objectweb.org/">Solutions</option><option value="http://middleware.objectweb.org/">Middleware</option><option value="http://forge.objectweb.org/">Project Forge</option><option value="http://myobjectweb.objectweb.org/">My ObjectWeb</option></select></td><td><input alt="Submit" border="0" onmouseover="MM_swapImage('ok','','../images/menu/boutonok2.gif',1)" onmouseout="MM_swapImgRestore()" src="../images/menu/boutonok1.gif" id="ok" name="Ok" type="image"></td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
</form>
|
||
|
<form target="_blank" action="http://www.google.com/custom" method="get">
|
||
|
<input value="S:http://www.objectweb.org/;GL:0;AH:center;LH:81;L:http://www.objectweb.org/media/owlogos/ObjectWeb-small.gif;LW:236;AWFID:48faba182d01f379;" name="cof" type="hidden"><input value="objectweb.org;mail-archive.objectweb.org;www.enhydra.org" name="domains" type="hidden"><input value="objectweb.org;www.enhydra.org" name="sitesearch" type="hidden">
|
||
|
<table rowspan="0" colspan="0">
|
||
|
<tr>
|
||
|
<td><input onblur="if (this.value=='') this.value='search'" onfocus="this.value=''" value="" maxlength="255" size="10" name="q" type="text"></td><td><input alt="Submit" onmouseover="MM_swapImage('search','','../images/menu/boutonsearch2.gif',1)" onmouseout="MM_swapImgRestore()" src="../images/menu/boutonsearch1.gif" id="search" name="sa" type="image"></td><td><a alt="Submit" onmouseover="MM_swapImage('print','','../images/menu/boutonprint2.gif',1)" onmouseout="MM_swapImgRestore()" target="_blank" href="faq_print.html"><img id="print" border="0" height="20" width="20" name="print" alt="Print" src="../images/menu/boutonprint1.gif"></a></td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
<p class="glose">
|
||
|
<strong><a target="_blank" class="lienglose" href="http://www.objectweb.org/search.html">Advanced</a></strong> - Powered by Google</p>
|
||
|
</form>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
<table cellpadding="0" cellspacing="0" border="0" width="100%" summary="">
|
||
|
<tr>
|
||
|
<td valign="top" width="20"><img alt=" " height="1" width="20" src="../images/pix.gif"></td><td valign="top" width="160"><img alt=" " height="1" width="160" src="../images/pix.gif"><br>
|
||
|
<br>
|
||
|
<br>
|
||
|
<br>
|
||
|
<br>
|
||
|
<p style="font-size: 16px; font-weight: bold; color: #433C7B;">ASM</p>
|
||
|
<p>
|
||
|
<span class="menutitre">Project Links</span>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../index.html">Home</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../download/index.html">Download</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../eclipse/index.html">Eclipse plugin</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="http://download.forge.objectweb.org/asm/asm-guide.pdf">User Guide</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="http://mail.ow2.org/wws/info/asm">Mailing Lists</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../license.html">License</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../history.html">History</a>
|
||
|
<br>
|
||
|
</p>
|
||
|
<p>
|
||
|
<span class="menutitre">Developers' Corner</span>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="http://forge.objectweb.org/projects/asm/">ObjectWeb Forge Site</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="http://forge.objectweb.org/plugins/scmsvn/index.php?group_id=23">SVN Repository</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="http://forge.objectweb.org/cvs/?group_id=23">CVS Repository (old)</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="http://forge.objectweb.org/tracker/?group_id=23">Issue Tracker</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../doc/developer-guide.html">Developer Guide</a>
|
||
|
<br>
|
||
|
</p>
|
||
|
<p>
|
||
|
<span class="menutitre">About</span>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../users.html">Users</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="../team.html">Team</a>
|
||
|
<br>
|
||
|
· <a class="menu" target="_self" href="mailto:asm-team@objectweb.org">Contacts</a>
|
||
|
<br>
|
||
|
</p>
|
||
|
</td><td align="left" width="100%" valign="top">
|
||
|
<h1>Frequently Asked Questions</h1>
|
||
|
|
||
|
<p>Here are some frequently asked questions about ASM, gathered by
|
||
|
<a href="mailto:m.proctor@bigfoot.com">Mark Proctor</a>.</p>
|
||
|
|
||
|
<ul>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q0">0. How do I start using ASM?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q1">1. How do I remove a method/field?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q2">2. How do I replace a method/field? I end up with duplicated members!</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q3">3. How do I make ASM calculate visitMaxs for me?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q4">4. Why do I get the [xxx] verifier error?"</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q5">5. How do I add my bytecode class to the system class loader?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q6">6. How do I rename my class?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q7">7. How do method descriptors work?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q8">8. How can ASM help me create my descriptor types?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q9">9. How do I generate Setters and Getters for my class?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q10">10. How do I get the bytecode of an existing class?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q11">11. How do I generate [some Java code] with ASM?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q12">12. How does the [xxx] bytecode instruction work?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q13">13. Is ASM thread safe?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q14">14. What is the earliest JDK required to use ASM?</a>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<a href="#Q15">15. How to resolve conflicts between different ASM API
|
||
|
versions available in a global classpath or within the same ClassLoader?</a>
|
||
|
</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q0"></a>0. How do I start using ASM?</h3>
|
||
|
|
||
|
|
||
|
<p>If you want to use ASM to generate classes from scratch, write a Java source
|
||
|
file that is representative of the classes you want to generate, compile it(*), and
|
||
|
then run the <a href="#Q10">ASMifier</a> on the compiled class to see the Java source code that
|
||
|
generates this class with ASM. If you are using Eclipse it is even easier,
|
||
|
thanks to the <a href="../eclipse/bco/index.html">Bytecode Outline</a> plugin.</p>
|
||
|
|
||
|
|
||
|
<p>If you want to use ASM to transform classes, write two Java source files -
|
||
|
first with and second without features that has to be added or removed and try
|
||
|
to keep other differences as minimal as you can, compile them(*), and then run the
|
||
|
<a href="#Q10">ASMifier</a> on both of them. Then compare the results with some visual diff tool.
|
||
|
If you are using Eclipse it is even easier, thanks to the compare tool of the
|
||
|
<a href="../eclipse/bco/index.html">Bytecode Outline</a> plugin.</p>
|
||
|
|
||
|
|
||
|
<p>(*) Note that javac may produce different code for different -target,
|
||
|
so you'll have to compile for your target environment, repeat that
|
||
|
excercise for all required target's or use the earliest bytecode version
|
||
|
if possible.</p>
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q1"></a>1. How do I remove a method/field?</h3>
|
||
|
|
||
|
|
||
|
<p>Use the ClassAdapter and return nothing:</p>
|
||
|
|
||
|
<pre> public FieldVisitor visitField (String name, ...) {
|
||
|
if (removeField(name)) {
|
||
|
// do nothing, in order to remove this field
|
||
|
return null;
|
||
|
} else {
|
||
|
// make the next visitor visit this field, in order to keep it
|
||
|
return super.visitField(name, ...);
|
||
|
}
|
||
|
}</pre>
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q2"></a>2. How do I replace a method/field? I end up with duplicated members!</h3>
|
||
|
|
||
|
|
||
|
<p>You must either return the replacement method/field when you visit the original one using the
|
||
|
ClassAdapter, or you must first remove the original method/field in the ClassAdapter (see
|
||
|
<a href="#Q1">"1. How do I remove a method/field?"</a>), and then add the new method/field
|
||
|
by calling a visit method on the ClassWriter.</p>
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q3"></a>3. How do I make ASM calculate visitMaxs for me?</h3>
|
||
|
|
||
|
|
||
|
<p>When calling the constructor for ClassWriter pass true. You must also
|
||
|
still include the visitMaxs instruction, but the values you give are
|
||
|
ignored, so visitMaxs(0,0) is fine.</p>
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q4"></a>4. Why do I get the [xxx] verifier error?</h3>
|
||
|
|
||
|
|
||
|
<p>If the message given by the JVM class verifier does not help you, you can
|
||
|
use the verifier provided by ASM. For example, if you use a wrong constant when
|
||
|
making "return" on a method, or if you do not use the appropriate LOAD or STORE
|
||
|
instruction, depending on the local variable type, the JVM class verifier gives
|
||
|
a "Register x contains wrong type" or "Expecting to find x on stack" error which
|
||
|
does not say anything about the instruction that caused the error. In this case
|
||
|
you can use the class verifier provided by ASM (asm-attrs.jar is needed with
|
||
|
ASM 2.x only):</p>
|
||
|
|
||
|
|
||
|
<p>
|
||
|
<code>java -cp "asm.jar;asm-tree.jar;asm-analysis.jar;asm-attrs.jar;asm-util.jar"
|
||
|
org.objectweb.asm.util.CheckClassAdapter org/domain/package/YourClass.class</code>
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<p>For example, in the helloworld example in the ASM distribution, if you replace
|
||
|
visitLdcInsn("Hello world!") with visitLdcInsn(new Integer(1234)) you get the following
|
||
|
error message when the generated class is verified as above:</p>
|
||
|
|
||
|
|
||
|
<pre>org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 2: Argument 1: expected Ljava/lang/String;, but found I
|
||
|
at org.objectweb.asm.tree.analysis.Analyzer.analyze(Unknown Source)
|
||
|
at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)
|
||
|
at org.objectweb.asm.util.CheckClassAdapter.main(Unknown Source)
|
||
|
...
|
||
|
main([Ljava/lang/String;)V
|
||
|
00000 String . : : GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||
|
00001 String . : PrintStream : LDC 1234
|
||
|
00002 String . : PrintStream I : INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
|
||
|
00003 ? : RETURN</pre>
|
||
|
|
||
|
|
||
|
<p>This shows that the error comes from instruction 2 in method main. The instruction list
|
||
|
shows that this instruction is INVOKEVIRTUAL. It also shows the types of the local variables
|
||
|
and of the operand stack values just before this instruction will be executed (here local
|
||
|
variable 0 contains a String, local variable 1 is not initialized, and the stack contains
|
||
|
a PrintStream and an int - I stands for int, as in type descriptors). As explained in the
|
||
|
error message, the println method called by
|
||
|
INVOKEVIRTUAL expects a String as first argument, but the stack value corresponding to this
|
||
|
argument is an int. Then either the INVOKEVIRTUAL instruction is wrong, or the instruction
|
||
|
that pushed the integer is wrong.</p>
|
||
|
|
||
|
|
||
|
<p>If your class is so "corrupted" that you cannot read it with a ClassReader,
|
||
|
try to generate it by using a CheckClassAdapter in front of a ClassWriter:</p>
|
||
|
|
||
|
<pre> ClassWriter cw = new ClassWriter(true);
|
||
|
ClassVisitor cv = new CheckClassAdapter(cw);
|
||
|
// generate your class here:
|
||
|
cv.visit(...);
|
||
|
...</pre>
|
||
|
|
||
|
<p>You will probably get an exception which will indicate why your generated class
|
||
|
is incorrect. For example, if you forget to call visit(...) (which can happen if you
|
||
|
forget to call super.visit(...) in a class adapter), the generated class
|
||
|
contains an invalid constant pool index, and ClassReader is unable to read it. If
|
||
|
you generate your class by using a CheckClassAdapter, as above, you get an
|
||
|
exception "Cannot visit member before visit has been called.", which shows that
|
||
|
you forgot to call the visit method.</p>
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q5"></a>5. How do I add my bytecode class to the system class loader?</h3>
|
||
|
|
||
|
|
||
|
<p>You must first have the security to do this, as defined in the policy
|
||
|
file - there are no security restrictions as default for a standard java
|
||
|
install. Use ClassLoader.defineClass, this however is a "protected" method, so
|
||
|
you must use reflection to gain access to it:</p>
|
||
|
|
||
|
<pre> private Class loadClass (byte[] b) {
|
||
|
//override classDefine (as it is protected) and define the class.
|
||
|
Class clazz = null;
|
||
|
try {
|
||
|
ClassLoader loader = ClassLoader.getSystemClassLoader();
|
||
|
Class cls = Class.forName("java.lang.ClassLoader");
|
||
|
java.lang.reflect.Method method =
|
||
|
cls.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class });
|
||
|
|
||
|
// protected method invocaton
|
||
|
method.setAccessible(true);
|
||
|
try {
|
||
|
Object[] args = new Object[] { className, b, new Integer(0), new Integer(b.length)};
|
||
|
clazz = (Class) method.invoke(loader, args);
|
||
|
} finally {
|
||
|
method.setAccessible(false);
|
||
|
}
|
||
|
} catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
System.exit(1);
|
||
|
}
|
||
|
return clazz;
|
||
|
}</pre>
|
||
|
|
||
|
<p>Alternatively you can create your own ClassLoader by extending the
|
||
|
existing class loader (example needed here).</p>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q6"></a>6. How do I rename my class?</h3>
|
||
|
|
||
|
|
||
|
<p>It is not enough to rename just the class, you must also rename all the
|
||
|
references to class members using the MethodAdapter.</p>
|
||
|
|
||
|
<pre>class ClassRenamer extends ClassAdapter implements Opcodes {
|
||
|
|
||
|
private Set oldNames;
|
||
|
private final String newName;
|
||
|
|
||
|
public ClassRenamer(ClassVisitor cv, Set oldNames, String newName) {
|
||
|
super(cv);
|
||
|
this.oldNames = oldNames;
|
||
|
this.newName = newName;
|
||
|
}
|
||
|
|
||
|
public void visit (int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||
|
oldNames.add(name);
|
||
|
cv.visit(version, ACC_PUBLIC, newName, signature, superName, interfaces);
|
||
|
}
|
||
|
|
||
|
public MethodVisitor visitMethod (int access, String name, String desc, String signature, String[] exceptions) {
|
||
|
MethodVisitor mv = cv.visitMethod(access, name, fixDesc(desc), fix(signature), exceptions);
|
||
|
if (mv != null && (access & ACC_ABSTRACT) == 0) {
|
||
|
mv = new MethodRenamer(mv);
|
||
|
}
|
||
|
return mv;
|
||
|
}
|
||
|
|
||
|
class MethodRenamer extends MethodAdapter {
|
||
|
|
||
|
public MethodRenamer (final MethodVisitor mv) {
|
||
|
super(mv);
|
||
|
}
|
||
|
|
||
|
public void visitTypeInsn (int i, String s) {
|
||
|
if (oldNames.contains(s)) {
|
||
|
s = newName;
|
||
|
}
|
||
|
mv.visitTypeInsn(i, s);
|
||
|
}
|
||
|
|
||
|
public void visitFieldInsn (int opcode, String owner, String name, String desc) {
|
||
|
if (oldNames.contains(owner)) {
|
||
|
mv.visitFieldInsn(opcode, newName, name, fix(desc));
|
||
|
} else {
|
||
|
mv.visitFieldInsn(opcode, owner, name, fix(desc));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void visitMethodInsn (int opcode, String owner, String name, String desc) {
|
||
|
if (oldNames.contains(owner)) {
|
||
|
mv.visitMethodInsn(opcode, newName, name, fix(desc));
|
||
|
} else {
|
||
|
mv.visitMethodInsn(opcode, owner, name, fix(desc));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private String fix (String s) {
|
||
|
if (s != null) {
|
||
|
Iterator it = oldNames.iterator();
|
||
|
String name;
|
||
|
while (it.hasNext()) {
|
||
|
name = (String) it.next();
|
||
|
if (s.indexOf(name) != -1) {
|
||
|
s = desc.replaceAll(name, newName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
}</pre>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q7"></a>7. How do method descriptors work?</h3>
|
||
|
|
||
|
|
||
|
<p>To understand this best it's good to read the source code of Type.java.
|
||
|
Here is a quick overview:</p>
|
||
|
|
||
|
<ul>
|
||
|
|
||
|
<li>Primitive representations:
|
||
|
<ul>
|
||
|
|
||
|
<li>'V' - void</li>
|
||
|
|
||
|
<li>'Z' - boolean</li>
|
||
|
|
||
|
<li>'C' - char</li>
|
||
|
|
||
|
<li>'B' - byte</li>
|
||
|
|
||
|
<li>'S' - short</li>
|
||
|
|
||
|
<li>'I' - int</li>
|
||
|
|
||
|
<li>'F' - float</li>
|
||
|
|
||
|
<li>'J' - long</li>
|
||
|
|
||
|
<li>'D' - double</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li>Class representations:
|
||
|
<ul>
|
||
|
|
||
|
<li>L<class>;</li>
|
||
|
|
||
|
<li>Ljava/io/ObjectOutput;</li>
|
||
|
|
||
|
<li>Ljava/lang/String;</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
<p>Examples:</p>
|
||
|
|
||
|
<ul>
|
||
|
|
||
|
<li>public void method()
|
||
|
<ul>
|
||
|
<li>
|
||
|
<code>cw.visitMethod(ACC_PUBLIC, methodName, "()V", null, null);</code>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</li>
|
||
|
|
||
|
<li>public void method(String s, int i)
|
||
|
<ul>
|
||
|
<li>
|
||
|
<code>cw.visitMethod(ACC_PUBLIC, methodName, "(Ljava/lang/String;I)V", null, null);</code>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</li>
|
||
|
|
||
|
<li>public String method(String s, int i, boolan flag)
|
||
|
<ul>
|
||
|
<li>
|
||
|
<code>cw.visitMethod(ACC_PUBLIC, methodName, "(Ljava/lang/String;IZ)Ljava/lang/String;", null, null);</code>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q8"></a>8. How can ASM help me create my descriptor types?</h3>
|
||
|
|
||
|
|
||
|
<p>Types.java provides the static method Type.getDescriptor, which takes a
|
||
|
Class as a parameter.</p>
|
||
|
|
||
|
<p>Examples:</p>
|
||
|
<ul>
|
||
|
|
||
|
<li>
|
||
|
<code>String desc = Type.getDescriptor(String.class);</code>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<code>String desc = Type.getDescriptor(int.class);</code>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<code>String desc = Type.getDescriptor(java.io.ObjectOutput.class);</code>
|
||
|
</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q9"></a>9. How do I generate Setters and Getters for my class?</h3>
|
||
|
|
||
|
|
||
|
<p>Use the following code (this assumes that visitMaxs are computed by ASM - see
|
||
|
<a href="#Q3">"3. How do I make ASM calculate visitMaxs for me?"</a>):</p>
|
||
|
|
||
|
<pre>void createSetter (String propertyName, String type, Class c) {
|
||
|
String methodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
|
||
|
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "(" + type + ")V", null, null);
|
||
|
mv.visitVarInsn(ALOAD, 0);
|
||
|
mv.visitVarInsn(Type.getType(c).getOpcode(ILOAD), 1);
|
||
|
mv.visitFieldInsn(PUTFIELD, className, propertyName, type);
|
||
|
mv.visitInsn(RETURN);
|
||
|
mv.visitMaxs(0, 0);
|
||
|
}
|
||
|
|
||
|
void createGetter (String propertyName, String returnType, Class c) {
|
||
|
String methodName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
|
||
|
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "()" + returnType, null, null);
|
||
|
mv.visitVarInsn(ALOAD, 0);
|
||
|
mv.visitFieldInsn(GETFIELD, internalClassName, propertyName, returnType);
|
||
|
mv.visitInsn(Type.getType(c).getOpcode(IRETURN));
|
||
|
mv.visitMaxs(0, 0);
|
||
|
}</pre>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q10"></a>10. How do I get the bytecode of an existing class?</h3>
|
||
|
|
||
|
|
||
|
<p>If you want the bytecode instructions themselves, use TraceClassVisitor. If you
|
||
|
want the ASM code to generate these bytecode instructions, use ASMifierClassVisitor.
|
||
|
Both classes provide a "main" method to allow them to be
|
||
|
called from the command line, passing your fully qualified class name as a
|
||
|
parameter.
|
||
|
Example:</p>
|
||
|
|
||
|
<p>
|
||
|
<code>java -classpath "asm.jar;asm-util.jar;yourjar.jar"
|
||
|
org.objectweb.asm.util.ASMifierClassVisitor org.domain.package.YourClass</code>
|
||
|
</p>
|
||
|
|
||
|
<p>or</p>
|
||
|
|
||
|
<p>
|
||
|
<code>java -classpath "asm.jar;asm-util.jar"
|
||
|
org.objectweb.asm.util.ASMifierClassVisitor org/domain/package/YourClass.class</code>
|
||
|
</p>
|
||
|
|
||
|
<p>Another, much easier method, if you are using Eclipse, is to use the
|
||
|
<a href="../eclipse/bco/index.html">Bytecode Outline</a> plugin.</p>
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q11"></a>11. How do I generate [some Java code] with ASM?</h3>
|
||
|
|
||
|
|
||
|
<p>If you want to know how to generate a synchronized block, a try catch
|
||
|
block, a finally statement, or any other Java construct, write the Java code
|
||
|
you want to generate in a temporary class, compile it with javac, and then
|
||
|
use the ASMifierClassVisitor to get the ASM code that will generate this class (see
|
||
|
<a href="#Q10">"10. How do I get the bytecode of an existing class?"</a>).
|
||
|
</p>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q12"></a>12. How does the [xxx] bytecode instruction work?</h3>
|
||
|
|
||
|
|
||
|
<p>See <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions.doc.html">chapter
|
||
|
6</a> of the Java Virtual Machine Specification.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q13"></a>13. Is ASM thread safe?</h3>
|
||
|
|
||
|
|
||
|
<p>The Type and ClassReader classes are thread safe, i.e. several threads can
|
||
|
use a single Type object or a single ClassReader object concurrently without
|
||
|
problems. The ClassWriter and MethodWriter classes are <em>not</em> thread safe,
|
||
|
i.e. a single class cannot be generated by several concurrent threads (but,
|
||
|
of course, several threads can generate distinct classes concurrently, if each
|
||
|
thread uses its own ClassWriter instance). In order to generate a single class
|
||
|
by using several concurrent threads, one should use ClassAdapter and
|
||
|
MethodAdapter instances that delegate to normal ClassWriter and MethodWriter
|
||
|
instances, and whose methods are all synchronized.</p>
|
||
|
|
||
|
<p>More generally, ClassVisitor and MethodVisitor implementations, such as
|
||
|
ClassWriter and ClassAdapter, do not have to be thread safe. However, non thread
|
||
|
safe visitors can be made thread safe just by using a synchronizing class
|
||
|
adapter in front of them.</p>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q14"></a>14. What is the earliest JDK required to use ASM?</h3>
|
||
|
|
||
|
|
||
|
<p>The org.objectweb.asm package should work with JDK 1.1, or even with JDK 1.0
|
||
|
if Type is not used. Indeed, this package only requires the following JDK classes
|
||
|
and methods:</p>
|
||
|
|
||
|
<ul>
|
||
|
|
||
|
<li>in java.io: InputStream, IOException (only in two constructors of
|
||
|
ClassReader)</li>
|
||
|
|
||
|
<li>in java.lang.reflect: Method (only in Type)</li>
|
||
|
|
||
|
<li>in java.lang:
|
||
|
<ul>
|
||
|
|
||
|
<li>Object, String, StringBuffer</li>
|
||
|
|
||
|
<li>Long, Double, Float, Void, Byte, Boolean ...</li>
|
||
|
|
||
|
<li>System.arraycopy</li>
|
||
|
|
||
|
<li>ClassLoader.getSystemClassLoader,
|
||
|
ClassLoader.getSystemResourceAsStream (only in one constructor of
|
||
|
ClassReader)</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
<p>The asm.util and asm.tree packages require JDK 1.2, since they use the
|
||
|
List interface and the ArrayList class.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
|
||
|
<h3>
|
||
|
<a name="Q15"></a>15. How to resolve conflicts between different ASM API
|
||
|
versions available in a global classpath or within the same ClassLoader?</h3>
|
||
|
|
||
|
|
||
|
<p>Tools and frameworks that are using ASM for bytecode
|
||
|
processing (e.g. Hibernate, CGLIB, AspectWerkz) should repackage
|
||
|
ASM code within their own name space. This can be automated with
|
||
|
<a href="http://tonicsystems.com/products/jarjar/">Jar Jar Links</a> tool.</p>
|
||
|
|
||
|
|
||
|
</td><td valign="top" width="10"><img alt=" " height="1" width="10" src="../images/pix.gif"></td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td valign="top" width="20"><img alt=" " height="1" width="20" src="../images/pix.gif"></td><td valign="top" width="160"><img alt=" " height="1" width="160" src="../images/pix.gif"></td><td valign="top"><img alt=" " height="1" width="465" src="../images/pix.gif"><br>
|
||
|
<address>Copyright © 1999-2005, <a href="http://www.objectweb.org/">ObjectWeb Consortium</a> | <a href="http://consortium.objectweb.org/contact.html">contact</a> | <a href="mailto:webmaster@objectweb.org">webmaster</a> | Last modified at 2009-02-16 10:31 AM</address>
|
||
|
</td><td valign="top" width="10"><img alt=" " height="1" width="10" src="../images/pix.gif"></td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
<br>
|
||
|
</body>
|
||
|
</html>
|