git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@161 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -0,0 +1,159 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.bytecode; | |||
import javassist.CtClass; | |||
import javassist.bytecode.annotation.AnnotationsWriter; | |||
import javassist.bytecode.annotation.MemberValue; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.DataInputStream; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
/** | |||
* A class representing <code>AnnotationDefault_attribute</code>. | |||
* | |||
* <p>For example, if you declare the following annotation type: | |||
* | |||
* <ul><pre> | |||
* @interface Author { | |||
* String name() default "Shakespeare"; | |||
* int age() default 99; | |||
* } | |||
* </pre></ul> | |||
* | |||
* <p>The defautl values of <code>name</code> and <code>age</code> | |||
* are stored as annotation default attributes in <code>Author.class</code>. | |||
* The following code snippet obtains the default value of <code>name</code>: | |||
* | |||
* <ul><pre> | |||
* ClassPool pool = ... | |||
* CtClass cc = pool.get("Author"); | |||
* CtMethod cm = cc.getDeclaredMethod("age"); | |||
* MethodInfo minfo = cm.getMethodInfo(); | |||
* AnnotationDefaultAttribute ada | |||
* = (AnnotationDefaultAttribute) | |||
* minfo.getAttribute(AnnotationDefaultAttribute.tag); | |||
* MemberValue value = ada.getDefaultValue()); // default value of age | |||
* </pre></ul> | |||
* | |||
* <p>If the following statement is executed after the code above, | |||
* the default value of age is set to 80: | |||
* | |||
* <ul><pre> | |||
* ada.setDefaultValue(new IntegerMemberValue(minfo.getConstPool(), 80)); | |||
* </pre></ul> | |||
* | |||
* @see AnnotationsAttribute | |||
* @see javassist.bytecode.annotation.MemberValue | |||
*/ | |||
public class AnnotationDefaultAttribute extends AttributeInfo { | |||
/** | |||
* The name of the <code>AnnotationDefault</code> attribute. | |||
*/ | |||
public static final String tag = "AnnotationDefault"; | |||
/** | |||
* Constructs an <code>AnnotationDefault_attribute</code>. | |||
* | |||
* @param cp constant pool | |||
* @param info the contents of this attribute. It does not | |||
* include <code>attribute_name_index</code> or | |||
* <code>attribute_length</code>. | |||
*/ | |||
public AnnotationDefaultAttribute(ConstPool cp, byte[] info) { | |||
super(cp, tag, info); | |||
} | |||
/** | |||
* Constructs an empty <code>AnnotationDefault_attribute</code>. | |||
* The default value can be set by <code>setDefaultValue()</code>. | |||
* | |||
* @param cp constant pool | |||
* @see #setDefaultValue(javassist.bytecode.annotation.MemberValue) | |||
*/ | |||
public AnnotationDefaultAttribute(ConstPool cp) { | |||
this(cp, new byte[] { 0, 0 }); | |||
} | |||
/** | |||
* @param n the attribute name. | |||
*/ | |||
AnnotationDefaultAttribute(ConstPool cp, int n, DataInputStream in) | |||
throws IOException | |||
{ | |||
super(cp, n, in); | |||
} | |||
/** | |||
* Copies this attribute and returns a new copy. | |||
*/ | |||
public AttributeInfo copy(ConstPool newCp, Map classnames) { | |||
AnnotationsAttribute.Copier copier | |||
= new AnnotationsAttribute.Copier(info, constPool, newCp, classnames); | |||
try { | |||
copier.memberValue(0); | |||
return new AnnotationDefaultAttribute(newCp, copier.close()); | |||
} | |||
catch (Exception e) { | |||
throw new RuntimeException(e.toString()); | |||
} | |||
} | |||
/** | |||
* Obtains the default value represented by this attribute. | |||
*/ | |||
public MemberValue getDefaultValue() | |||
{ | |||
try { | |||
return new AnnotationsAttribute.Parser(info, constPool) | |||
.parseMemberValue(); | |||
} | |||
catch (Exception e) { | |||
throw new RuntimeException(e.toString()); | |||
} | |||
} | |||
/** | |||
* Changes the default value represented by this attribute. | |||
* | |||
* @param value the new value. | |||
* @see javassist.bytecode.annotation.Annotation#createMemberValue(ConstPool, CtClass) | |||
*/ | |||
public void setDefaultValue(MemberValue value) { | |||
ByteArrayOutputStream output = new ByteArrayOutputStream(); | |||
AnnotationsWriter writer = new AnnotationsWriter(output, constPool); | |||
try { | |||
value.write(writer); | |||
writer.close(); | |||
} | |||
catch (IOException e) { | |||
throw new RuntimeException(e); // should never reach here. | |||
} | |||
set(output.toByteArray()); | |||
} | |||
/** | |||
* Returns a string representation of this object. | |||
*/ | |||
public String toString() { | |||
return getDefaultValue().toString(); | |||
} | |||
} |
@@ -38,12 +38,14 @@ import javassist.bytecode.annotation.*; | |||
* <p>For example, | |||
* | |||
* <ul><pre> | |||
* import javassist.bytecode.annotation.Annotation; | |||
* : | |||
* CtMethod m = ... ; | |||
* MethodInfo minfo = m.getMethodInfo(); | |||
* AnnotationsAttribute attr = (AnnotationsAttribute) | |||
* minfo.getAttribute(AnnotationsAttribute.visibleTag); | |||
* minfo.getAttribute(AnnotationsAttribute.invisibleTag); | |||
* Annotation an = attr.getAnnotation("Author"); | |||
* String s = ((StringMemberValue)a.getMemberValue("name")).getValue(); | |||
* String s = ((StringMemberValue)an.getMemberValue("name")).getValue(); | |||
* System.out.println("@Author(name=" + s + ")"); | |||
* </pre></ul> | |||
* | |||
@@ -51,6 +53,31 @@ import javassist.bytecode.annotation.*; | |||
* from the <code>MethodInfo</code> object specified by <code>minfo</code>. | |||
* Then, it prints the value of <code>name</code> in <code>Author</code>. | |||
* | |||
* <p>If the annotation type <code>Author</code> is annotated by a meta annotation: | |||
* | |||
* <ul><pre> | |||
* @Retention(RetentionPolicy.RUNTIME) | |||
* </pre></ul> | |||
* | |||
* <p>Then <code>Author</code> is visible at runtime. Therefore, the third | |||
* statement of the code snippet above must be changed into: | |||
* | |||
* <ul><pre> | |||
* AnnotationsAttribute attr = (AnnotationsAttribute) | |||
* minfo.getAttribute(AnnotationsAttribute.visibleTag); | |||
* </pre></ul> | |||
* | |||
* <p>The attribute tag must be <code>visibleTag</code> instead of | |||
* <code>invisibleTag</code>. | |||
* | |||
* <p>If the member value of an annotation is not specified, the default value | |||
* is used as that member value. If so, <code>getMemberValue()</code> in | |||
* <code>Annotation</code> returns <code>null</code> | |||
* since the default value is not included in the | |||
* <code>AnnotationsAttribute</code>. It is included in the | |||
* <code>AnnotationDefaultAttribute</code> of the method declared in the | |||
* annotation type. | |||
* | |||
* <p>If you want to record a new AnnotationAttribute object, execute the | |||
* following snippet: | |||
* | |||
@@ -65,6 +92,7 @@ import javassist.bytecode.annotation.*; | |||
* cf.addAttribute(attr); | |||
* </pre></ul> | |||
* | |||
* @see AnnotationDefaultAttribute | |||
* @see javassist.bytecode.annotation.Annotation | |||
*/ | |||
public class AnnotationsAttribute extends AttributeInfo { | |||
@@ -448,7 +476,7 @@ public class AnnotationsAttribute extends AttributeInfo { | |||
Annotation[][] allParams; // all parameters | |||
Annotation[] allAnno; // all annotations | |||
Annotation currentAnno; // current annotation | |||
MemberValue memberValue; | |||
MemberValue currentMember; // current member | |||
/** | |||
* Constructs a parser. This parser constructs a parse tree of | |||
@@ -472,6 +500,11 @@ public class AnnotationsAttribute extends AttributeInfo { | |||
return allAnno; | |||
} | |||
MemberValue parseMemberValue() throws Exception { | |||
memberValue(0); | |||
return currentMember; | |||
} | |||
void parameters(int numParam, int pos) throws Exception { | |||
Annotation[][] params = new Annotation[numParam][]; | |||
for (int i = 0; i < numParam; ++i) { | |||
@@ -500,7 +533,7 @@ public class AnnotationsAttribute extends AttributeInfo { | |||
int memberValuePair(int pos, int nameIndex) throws Exception { | |||
pos = super.memberValuePair(pos, nameIndex); | |||
currentAnno.addMemberValue(nameIndex, memberValue); | |||
currentAnno.addMemberValue(nameIndex, currentMember); | |||
return pos; | |||
} | |||
@@ -539,27 +572,27 @@ public class AnnotationsAttribute extends AttributeInfo { | |||
throw new RuntimeException("unknown tag:" + tag); | |||
} | |||
memberValue = m; | |||
currentMember = m; | |||
super.constValueMember(tag, index); | |||
} | |||
void enumMemberValue(int typeNameIndex, int constNameIndex) | |||
throws Exception | |||
{ | |||
memberValue = new EnumMemberValue(typeNameIndex, | |||
currentMember = new EnumMemberValue(typeNameIndex, | |||
constNameIndex, pool); | |||
super.enumMemberValue(typeNameIndex, constNameIndex); | |||
} | |||
void classMemberValue(int index) throws Exception { | |||
memberValue = new ClassMemberValue(index, pool); | |||
currentMember = new ClassMemberValue(index, pool); | |||
super.classMemberValue(index); | |||
} | |||
int annotationMemberValue(int pos) throws Exception { | |||
Annotation anno = currentAnno; | |||
pos = super.annotationMemberValue(pos); | |||
memberValue = new AnnotationMemberValue(currentAnno, pool); | |||
currentMember = new AnnotationMemberValue(currentAnno, pool); | |||
currentAnno = anno; | |||
return pos; | |||
} | |||
@@ -569,11 +602,11 @@ public class AnnotationsAttribute extends AttributeInfo { | |||
MemberValue[] elements = new MemberValue[num]; | |||
for (int i = 0; i < num; ++i) { | |||
pos = memberValue(pos); | |||
elements[i] = memberValue; | |||
elements[i] = currentMember; | |||
} | |||
amv.setValue(elements); | |||
memberValue = amv; | |||
currentMember = amv; | |||
return pos; | |||
} | |||
} |
@@ -72,7 +72,9 @@ public class AttributeInfo { | |||
int name = in.readUnsignedShort(); | |||
String nameStr = cp.getUtf8Info(name); | |||
if (nameStr.charAt(0) < 'L') { | |||
if (nameStr.equals(CodeAttribute.tag)) | |||
if (nameStr.equals(AnnotationDefaultAttribute.tag)) | |||
return new AnnotationDefaultAttribute(cp, name, in); | |||
else if (nameStr.equals(CodeAttribute.tag)) | |||
return new CodeAttribute(cp, name, in); | |||
else if (nameStr.equals(ConstantAttribute.tag)) | |||
return new ConstantAttribute(cp, name, in); |
@@ -109,36 +109,42 @@ public class Annotation { | |||
} | |||
} | |||
private MemberValue createMemberValue(ConstPool cp, CtClass returnType) | |||
/** | |||
* Makes an instance of <code>MemberValue</code>. | |||
* | |||
* @param cp the constant pool table. | |||
* @param type the type of the member. | |||
*/ | |||
public static MemberValue createMemberValue(ConstPool cp, CtClass type) | |||
throws javassist.NotFoundException | |||
{ | |||
if (returnType == CtClass.booleanType) | |||
if (type == CtClass.booleanType) | |||
return new BooleanMemberValue(cp); | |||
else if (returnType == CtClass.byteType) | |||
else if (type == CtClass.byteType) | |||
return new ByteMemberValue(cp); | |||
else if (returnType == CtClass.charType) | |||
else if (type == CtClass.charType) | |||
return new CharMemberValue(cp); | |||
else if (returnType == CtClass.shortType) | |||
else if (type == CtClass.shortType) | |||
return new ShortMemberValue(cp); | |||
else if (returnType == CtClass.intType) | |||
else if (type == CtClass.intType) | |||
return new IntegerMemberValue(cp); | |||
else if (returnType == CtClass.longType) | |||
else if (type == CtClass.longType) | |||
return new LongMemberValue(cp); | |||
else if (returnType == CtClass.floatType) | |||
else if (type == CtClass.floatType) | |||
return new FloatMemberValue(cp); | |||
else if (returnType == CtClass.doubleType) | |||
else if (type == CtClass.doubleType) | |||
return new DoubleMemberValue(cp); | |||
else if (returnType.getName().equals("java.lang.Class")) | |||
else if (type.getName().equals("java.lang.Class")) | |||
return new ClassMemberValue(cp); | |||
else if (returnType.getName().equals("java.lang.String")) | |||
else if (type.getName().equals("java.lang.String")) | |||
return new StringMemberValue(cp); | |||
else if (returnType.isArray()) { | |||
CtClass arrayType = returnType.getComponentType(); | |||
MemberValue type = createMemberValue(cp, arrayType); | |||
return new ArrayMemberValue(type, cp); | |||
else if (type.isArray()) { | |||
CtClass arrayType = type.getComponentType(); | |||
MemberValue member = createMemberValue(cp, arrayType); | |||
return new ArrayMemberValue(member, cp); | |||
} | |||
else if (returnType.isInterface()) { | |||
Annotation info = new Annotation(cp, returnType); | |||
else if (type.isInterface()) { | |||
Annotation info = new Annotation(cp, type); | |||
return new AnnotationMemberValue(info, cp); | |||
} | |||
else { | |||
@@ -146,7 +152,7 @@ public class Annotation { | |||
// but JBoss has an Annotation Compiler for JDK 1.4 | |||
// and I want it to work with that. - Bill Burke | |||
EnumMemberValue emv = new EnumMemberValue(cp); | |||
emv.setType(returnType.getName()); | |||
emv.setType(type.getName()); | |||
return emv; | |||
} | |||
} |
@@ -63,7 +63,10 @@ public class AnnotationMemberValue extends MemberValue { | |||
return value.toString(); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.annotationValue(); | |||
value.write(writer); | |||
} |
@@ -89,7 +89,10 @@ public class ArrayMemberValue extends MemberValue { | |||
return buf.toString(); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
int num = values.length; | |||
writer.arrayValue(num); | |||
for (int i = 0; i < num; ++i) |
@@ -76,7 +76,10 @@ public class BooleanMemberValue extends MemberValue { | |||
return getValue() ? "true" : "false"; | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -76,7 +76,10 @@ public class ByteMemberValue extends MemberValue { | |||
return Byte.toString(getValue()); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -77,7 +77,10 @@ public class CharMemberValue extends MemberValue { | |||
return Character.toString(getValue()); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -85,7 +85,10 @@ public class ClassMemberValue extends MemberValue { | |||
return "<" + getValue() + " class>"; | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.classInfoIndex(valueIndex); | |||
} | |||
@@ -23,7 +23,7 @@ import java.io.IOException; | |||
* | |||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> | |||
* @author Shigeru Chiba | |||
* @version $Revision: 1.4 $ | |||
* @version $Revision: 1.5 $ | |||
*/ | |||
public class DoubleMemberValue extends MemberValue { | |||
int valueIndex; | |||
@@ -78,7 +78,10 @@ public class DoubleMemberValue extends MemberValue { | |||
return Double.toString(getValue()); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -88,7 +88,10 @@ public class EnumMemberValue extends MemberValue { | |||
return getType() + "." + getValue(); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.enumConstValue(getType(), getValue()); | |||
} | |||
@@ -23,7 +23,7 @@ import java.io.IOException; | |||
* | |||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> | |||
* @author Shigeru Chiba | |||
* @version $Revision: 1.4 $ | |||
* @version $Revision: 1.5 $ | |||
*/ | |||
public class FloatMemberValue extends MemberValue { | |||
int valueIndex; | |||
@@ -78,7 +78,10 @@ public class FloatMemberValue extends MemberValue { | |||
return Float.toString(getValue()); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -83,7 +83,10 @@ public class IntegerMemberValue extends MemberValue { | |||
return Integer.toString(getValue()); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -77,7 +77,10 @@ public class LongMemberValue extends MemberValue { | |||
return Long.toString(getValue()); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -38,7 +38,10 @@ public abstract class MemberValue { | |||
*/ | |||
public abstract void accept(MemberValueVisitor visitor); | |||
abstract void write(AnnotationsWriter w) throws IOException; | |||
/** | |||
* Writes the value. | |||
*/ | |||
public abstract void write(AnnotationsWriter w) throws IOException; | |||
} | |||
@@ -77,7 +77,10 @@ public class ShortMemberValue extends MemberValue { | |||
return Short.toString(getValue()); | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||
@@ -77,7 +77,10 @@ public class StringMemberValue extends MemberValue { | |||
return "\"" + getValue() + "\""; | |||
} | |||
void write(AnnotationsWriter writer) throws IOException { | |||
/** | |||
* Writes the value. | |||
*/ | |||
public void write(AnnotationsWriter writer) throws IOException { | |||
writer.constValueIndex(getValue()); | |||
} | |||