diff options
Diffstat (limited to 'src/main/javassist/bytecode')
-rw-r--r-- | src/main/javassist/bytecode/AnnotationsAttribute.java | 1068 | ||||
-rw-r--r-- | src/main/javassist/bytecode/MethodInfo.java | 755 | ||||
-rw-r--r-- | src/main/javassist/bytecode/annotation/ClassMemberValue.java | 132 |
3 files changed, 1057 insertions, 898 deletions
diff --git a/src/main/javassist/bytecode/AnnotationsAttribute.java b/src/main/javassist/bytecode/AnnotationsAttribute.java index a6dfe87a..2483c01b 100644 --- a/src/main/javassist/bytecode/AnnotationsAttribute.java +++ b/src/main/javassist/bytecode/AnnotationsAttribute.java @@ -15,30 +15,46 @@ package javassist.bytecode; -import java.util.Map; -import java.io.IOException; -import java.io.DataInputStream; -import java.io.ByteArrayOutputStream; +import javassist.bytecode.annotation.Annotation; +import javassist.bytecode.annotation.AnnotationMemberValue; +import javassist.bytecode.annotation.AnnotationsWriter; +import javassist.bytecode.annotation.ArrayMemberValue; +import javassist.bytecode.annotation.BooleanMemberValue; +import javassist.bytecode.annotation.ByteMemberValue; +import javassist.bytecode.annotation.CharMemberValue; +import javassist.bytecode.annotation.ClassMemberValue; +import javassist.bytecode.annotation.DoubleMemberValue; +import javassist.bytecode.annotation.EnumMemberValue; +import javassist.bytecode.annotation.FloatMemberValue; +import javassist.bytecode.annotation.IntegerMemberValue; +import javassist.bytecode.annotation.LongMemberValue; +import javassist.bytecode.annotation.MemberValue; +import javassist.bytecode.annotation.ShortMemberValue; +import javassist.bytecode.annotation.StringMemberValue; -import javassist.bytecode.annotation.*; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; /** * A class representing * <code>RuntimeVisibleAnnotations_attribute</code> and * <code>RuntimeInvisibleAnnotations_attribute</code>. - * + * <p/> * <p>To obtain an AnnotationAttribute object, invoke * <code>getAttribute(AnnotationsAttribute.invisibleTag)</code> * in <code>ClassFile</code>, <code>MethodInfo</code>, * or <code>FieldInfo</code>. The obtained attribute is a - * runtime invisible annotations attribute. + * runtime invisible annotations attribute. * If the parameter is * <code>AnnotationAttribute.visibleTag</code>, then the obtained * attribute is a runtime visible one. - * + * <p/> * <p>If you want to record a new AnnotationAttribute object, execute the * following snippet: - * + * <p/> * <ul><pre> * ClassFile cf = ... ; * ConstPool cp = cf.getConstPool(); @@ -50,471 +66,571 @@ import javassist.bytecode.annotation.*; * cf.addAttribute(attr); * </pre></ul> */ -public class AnnotationsAttribute extends AttributeInfo { - /** - * The name of the <code>RuntimeVisibleAnnotations</code> attribute. - */ - public static final String visibleTag = "RuntimeVisibleAnnotations"; - - /** - * The name of the <code>RuntimeInvisibleAnnotations</code> attribute. - */ - public static final String invisibleTag = "RuntimeInvisibleAnnotations"; - - /** - * Constructs a <code>Runtime(In)VisisbleAnnotations_attribute</code>. - * - * @param cp constant pool - * @param attrname attribute name (<code>visibleTag</code> or - * <code>invisibleTag</code>). - * @param info the contents of this attribute. It does not - * include <code>attribute_name_index</code> or - * <code>attribute_length</code>. - */ - public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info) { - super(cp, attrname, info); - } - - /** - * Constructs an empty - * <code>Runtime(In)VisisbleAnnotations_attribute</code>. - * A new annotation can be later added to the created attribute - * by <code>setAnnotations()</code>. - * - * @param cp constant pool - * @param attrname attribute name (<code>visibleTag</code> or - * <code>invisibleTag</code>). - * @see #setAnnotations(Annotation[]) - */ - public AnnotationsAttribute(ConstPool cp, String attrname) { - this(cp, attrname, new byte[] { 0, 0 }); - } - - /** - * @param n the attribute name. - */ - AnnotationsAttribute(ConstPool cp, int n, DataInputStream in) - throws IOException - { - super(cp, n, in); - } - - /** - * Returns <code>num_annotations</code>. - */ - public int numAnnotations() { - return ByteArray.readU16bit(info, 0); - } - - /** - * Copies this attribute and returns a new copy. - */ - public AttributeInfo copy(ConstPool newCp, Map classnames) { - Copier copier = new Copier(info, constPool, newCp, classnames); - try { - copier.annotationArray(); - return new AnnotationsAttribute(newCp, getName(), copier.close()); - } - catch (Exception e) { - throw new RuntimeException(e.toString()); - } - } - - /** - * Parses the annotations and returns a data structure representing - * that parsed annotations. Note that changes of the node values of the - * returned tree are not reflected on the annotations represented by - * this object unless the tree is copied back to this object by - * <code>setAnnotations()</code>. - * - * @see #setAnnotations(Annotation[]) - */ - public Annotation[] getAnnotations() { - try { - return new Parser(info, constPool).parseAnnotations(); - } - catch (Exception e) { - throw new RuntimeException(e.toString()); - } - } - - /** - * Changes the annotations represented by this object according to - * the given array of <code>Annotation</code> objects. - * - * @param annotations the data structure representing the - * new annotations. - */ - public void setAnnotations(Annotation[] annotations) { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - AnnotationsWriter writer = new AnnotationsWriter(output, constPool); - try { - int n = annotations.length; - writer.numAnnotations(n); - for (int i = 0; i < n; ++i) - annotations[i].write(writer); - - writer.close(); - } - catch (IOException e) { - throw new RuntimeException(e); // should never reach here. - } - - set(output.toByteArray()); - } - - /** - * Changes the annotations. A call to this method is equivalent to: - * <ul><pre>setAnnotations(new Annotation[] { annotation })</pre></ul> - * - * @param annotation the data structure representing - * the new annotation. - */ - public void setAnnotation(Annotation annotation) { - setAnnotations(new Annotation[] { annotation }); - } - - /** - * Returns a string representation of this object. - */ - public String toString() { - Annotation[] a = getAnnotations(); - StringBuffer sbuf = new StringBuffer(); - int i = 0; - while (i < a.length) { - sbuf.append(a[i++].toString()); - if (i != a.length) - sbuf.append(", "); - } - - return sbuf.toString(); - } - - static class Walker { - byte[] info; - - Walker(byte[] attrInfo) { - info = attrInfo; - } - - final void parameters() throws Exception { - int numParam = info[0] & 0xff; - parameters(numParam, 1); - } - - void parameters(int numParam, int pos) throws Exception { - for (int i = 0; i < numParam; ++i) - pos = annotationArray(pos); - } - - final void annotationArray() throws Exception { - annotationArray(0); - } - - final int annotationArray(int pos) throws Exception { - int num = ByteArray.readU16bit(info, pos); - return annotationArray(pos + 2, num); - } - - int annotationArray(int pos, int num) throws Exception { - for (int i = 0; i < num; ++i) - pos = annotation(pos); - - return pos; - } - - final int annotation(int pos) throws Exception { - int type = ByteArray.readU16bit(info, pos); - int numPairs = ByteArray.readU16bit(info, pos + 2); - return annotation(pos + 4, type, numPairs); - } - - int annotation(int pos, int type, int numPairs) throws Exception { - for (int j = 0; j < numPairs; ++j) - pos = memberValuePair(pos); - - return pos; - } - - final int memberValuePair(int pos) throws Exception { - int nameIndex = ByteArray.readU16bit(info, pos); - return memberValuePair(pos + 2, nameIndex); - } - - int memberValuePair(int pos, int nameIndex) throws Exception { - return memberValue(pos); - } - - final int memberValue(int pos) throws Exception { - int tag = info[pos] & 0xff; - if (tag == 'e') { - int typeNameIndex = ByteArray.readU16bit(info, pos + 1); - int constNameIndex = ByteArray.readU16bit(info, pos + 3); - enumMemberValue(typeNameIndex, constNameIndex); - return pos + 5; - } - else if (tag == 'c') { - int index = ByteArray.readU16bit(info, pos + 1); - classMemberValue(index); - return pos + 3; - } - else if (tag == '@') - return annotationMemberValue(pos + 1); - else if (tag == '[') { - int num = ByteArray.readU16bit(info, pos + 1); - return arrayMemberValue(pos + 3, num); - } - else { // primitive types or String. - int index = ByteArray.readU16bit(info, pos + 1); - constValueMember(tag, index); - return pos + 3; - } - } - - void constValueMember(int tag, int index) throws Exception {} - - void enumMemberValue(int typeNameIndex, int constNameIndex) - throws Exception {} - - void classMemberValue(int index) throws Exception {} - - int annotationMemberValue(int pos) throws Exception { - return annotation(pos); - } - - int arrayMemberValue(int pos, int num) throws Exception { - for (int i = 0; i < num; ++i) { - pos = memberValue(pos); - } - - return pos; - } - } - - static class Copier extends Walker { - ByteArrayOutputStream output; - AnnotationsWriter writer; - ConstPool srcPool, destPool; - Map classnames; - - /** - * Constructs a copier. This copier renames some class names - * into the new names specified by <code>map</code> when it copies - * an annotation attribute. - * - * @param info the source attribute. - * @param src the constant pool of the source class. - * @param dest the constant pool of the destination class. - * @param map pairs of replaced and substituted class names. - * It can be null. - */ - Copier(byte[] info, ConstPool src, ConstPool dest, Map map) { - super(info); - output = new ByteArrayOutputStream(); - writer = new AnnotationsWriter(output, dest); - srcPool = src; - destPool = dest; - classnames = map; - } - - byte[] close() throws IOException { - writer.close(); - return output.toByteArray(); - } - - void parameters(int numParam, int pos) throws Exception { - writer.numParameters(numParam); - super.parameters(numParam, pos); - } - - int annotationArray(int pos, int num) throws Exception { - writer.numAnnotations(num); - return super.annotationArray(pos, num); - } - - int annotation(int pos, int type, int numPairs) throws Exception { - writer.annotation(copy(type), numPairs); - return super.annotation(pos, type, numPairs); - } - - int memberValuePair(int pos, int nameIndex) throws Exception { - writer.memberValuePair(copy(nameIndex)); - return super.memberValuePair(pos, nameIndex); - } - - void constValueMember(int tag, int index) throws Exception { - writer.constValueIndex(tag, copy(index)); - super.constValueMember(tag, index); - } - - void enumMemberValue(int typeNameIndex, int constNameIndex) - throws Exception - { - writer.enumConstValue(copy(typeNameIndex), copy(constNameIndex)); - super.enumMemberValue(typeNameIndex, constNameIndex); - } - - void classMemberValue(int index) throws Exception { - writer.classInfoIndex(copy(index)); - super.classMemberValue(index); - } - - int annotationMemberValue(int pos) throws Exception { - writer.annotationValue(); - return super.annotationMemberValue(pos); - } - - int arrayMemberValue(int pos, int num) throws Exception { - writer.arrayValue(num); - return super.arrayMemberValue(pos, num); - } - - /** - * Copies a constant pool entry into the destination constant pool - * and returns the index of the copied entry. - * - * @param srcIndex the index of the copied entry into the source - * constant pool. - * @return the index of the copied item into the destination - * constant pool. - */ - int copy(int srcIndex) { - return srcPool.copy(srcIndex, destPool, classnames); - } - } - - static class Parser extends Walker { - ConstPool pool; - Annotation[][] allParams; // all parameters - Annotation[] allAnno; // all annotations - Annotation currentAnno; // current annotation - MemberValue memberValue; - - /** - * Constructs a parser. This parser constructs a parse tree of - * the annotations. - * - * @param info the attribute. - * @param src the constant pool. - */ - Parser(byte[] info, ConstPool cp) { - super(info); - pool = cp; - } - - Annotation[][] parseParameters() throws Exception { - parameters(); - return allParams; - } - - Annotation[] parseAnnotations() throws Exception { - annotationArray(); - return allAnno; - } - - void parameters(int numParam, int pos) throws Exception { - Annotation[][] params = new Annotation[numParam][]; - for (int i = 0; i < numParam; ++i) { - pos = annotationArray(pos); - params[i] = allAnno; - } - - allParams = params; - } - - int annotationArray(int pos, int num) throws Exception { - Annotation[] array = new Annotation[num]; - for (int i = 0; i < num; ++i) { - pos = annotation(pos); - array[i] = currentAnno; - } - - allAnno = array; - return pos; - } - - int annotation(int pos, int type, int numPairs) throws Exception { - currentAnno = new Annotation(type, pool); - return super.annotation(pos, type, numPairs); - } - - int memberValuePair(int pos, int nameIndex) throws Exception { - pos = super.memberValuePair(pos, nameIndex); - currentAnno.addMemberValue(nameIndex, memberValue); - return pos; - } - - void constValueMember(int tag, int index) throws Exception { - MemberValue m; - ConstPool cp = pool; - switch (tag) { - case 'B' : - m = new ByteMemberValue(index, cp); - break; - case 'C' : - m = new CharMemberValue(index, cp); - break; - case 'D' : - m = new DoubleMemberValue(index, cp); - break; - case 'F' : - m = new FloatMemberValue(index, cp); - break; - case 'I' : - m = new IntegerMemberValue(index, cp); - break; - case 'J' : - m = new LongMemberValue(index, cp); - break; - case 'S' : - m = new ShortMemberValue(index, cp); - break; - case 'Z' : - m = new BooleanMemberValue(index, cp); - break; - case 's' : - m = new StringMemberValue(index, cp); - break; - default : - throw new RuntimeException("unknown tag:" + tag); - } - - memberValue = m; - super.constValueMember(tag, index); - } - - void enumMemberValue(int typeNameIndex, int constNameIndex) - throws Exception - { - memberValue = new EnumMemberValue(typeNameIndex, - constNameIndex, pool); - super.enumMemberValue(typeNameIndex, constNameIndex); - } - - void classMemberValue(int index) throws Exception { - memberValue = 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); - currentAnno = anno; - return pos; - } - - int arrayMemberValue(int pos, int num) throws Exception { - ArrayMemberValue amv = new ArrayMemberValue(pool); - MemberValue[] elements = new MemberValue[num]; - for (int i = 0; i < num; ++i) { - pos = memberValue(pos); - elements[i] = memberValue; - } - - amv.setValue(elements); - memberValue = amv; - return pos; - } - } +public class AnnotationsAttribute extends AttributeInfo +{ + /** + * The name of the <code>RuntimeVisibleAnnotations</code> attribute. + */ + public static final String visibleTag = "RuntimeVisibleAnnotations"; + + /** + * The name of the <code>RuntimeInvisibleAnnotations</code> attribute. + */ + public static final String invisibleTag = "RuntimeInvisibleAnnotations"; + + private HashMap annotationMap; + + /** + * Constructs a <code>Runtime(In)VisisbleAnnotations_attribute</code>. + * + * @param cp constant pool + * @param attrname attribute name (<code>visibleTag</code> or + * <code>invisibleTag</code>). + * @param info the contents of this attribute. It does not + * include <code>attribute_name_index</code> or + * <code>attribute_length</code>. + */ + public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info) + { + super(cp, attrname, info); + } + + /** + * Constructs an empty + * <code>Runtime(In)VisisbleAnnotations_attribute</code>. + * A new annotation can be later added to the created attribute + * by <code>setAnnotations()</code>. + * + * @param cp constant pool + * @param attrname attribute name (<code>visibleTag</code> or + * <code>invisibleTag</code>). + * @see #setAnnotations(Annotation[]) + */ + public AnnotationsAttribute(ConstPool cp, String attrname) + { + this(cp, attrname, new byte[]{0, 0}); + } + + /** + * @param n the attribute name. + */ + AnnotationsAttribute(ConstPool cp, int n, DataInputStream in) + throws IOException + { + super(cp, n, in); + } + + /** + * Returns <code>num_annotations</code>. + */ + public int numAnnotations() + { + return ByteArray.readU16bit(info, 0); + } + + /** + * Copies this attribute and returns a new copy. + */ + public AttributeInfo copy(ConstPool newCp, Map classnames) + { + Copier copier = new Copier(info, constPool, newCp, classnames); + try + { + copier.annotationArray(); + return new AnnotationsAttribute(newCp, getName(), copier.close()); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } + + public Annotation getAnnotation(String type) + { + Annotation[] annotations = getAnnotations(); + for (int i = 0; i < annotations.length; i++) + { + if (annotations[i].getTypeName().equals(type)) return annotations[i]; + } + return null; + } + + public void addAnnotation(Annotation annotation) + { + String type = annotation.getTypeName(); + Annotation[] annotations = getAnnotations(); + for (int i = 0; i < annotations.length; i++) + { + if (annotations[i].getTypeName().equals(type)) + { + annotations[i] = annotation; + setAnnotations(annotations); + return; + } + } + Annotation[] newlist = new Annotation[annotations.length + 1]; + System.arraycopy(annotations, 0, newlist, 0, annotations.length); + newlist[annotations.length] = annotation; + setAnnotations(newlist); + } + + /** + * Parses the annotations and returns a data structure representing + * that parsed annotations. Note that changes of the node values of the + * returned tree are not reflected on the annotations represented by + * this object unless the tree is copied back to this object by + * <code>setAnnotations()</code>. + * + * @see #setAnnotations(Annotation[]) + */ + public Annotation[] getAnnotations() + { + try + { + return new Parser(info, constPool).parseAnnotations(); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } + + /** + * Changes the annotations represented by this object according to + * the given array of <code>Annotation</code> objects. + * + * @param annotations the data structure representing the + * new annotations. + */ + public void setAnnotations(Annotation[] annotations) + { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + AnnotationsWriter writer = new AnnotationsWriter(output, constPool); + try + { + int n = annotations.length; + writer.numAnnotations(n); + for (int i = 0; i < n; ++i) + annotations[i].write(writer); + + writer.close(); + } + catch (IOException e) + { + throw new RuntimeException(e); // should never reach here. + } + + set(output.toByteArray()); + } + + /** + * Changes the annotations. A call to this method is equivalent to: + * <ul><pre>setAnnotations(new Annotation[] { annotation })</pre></ul> + * + * @param annotation the data structure representing + * the new annotation. + */ + public void setAnnotation(Annotation annotation) + { + setAnnotations(new Annotation[]{annotation}); + } + + /** + * Returns a string representation of this object. + */ + public String toString() + { + Annotation[] a = getAnnotations(); + StringBuffer sbuf = new StringBuffer(); + int i = 0; + while (i < a.length) + { + sbuf.append(a[i++].toString()); + if (i != a.length) + sbuf.append(", "); + } + + return sbuf.toString(); + } + + static class Walker + { + byte[] info; + + Walker(byte[] attrInfo) + { + info = attrInfo; + } + + final void parameters() throws Exception + { + int numParam = info[0] & 0xff; + parameters(numParam, 1); + } + + void parameters(int numParam, int pos) throws Exception + { + for (int i = 0; i < numParam; ++i) + pos = annotationArray(pos); + } + + final void annotationArray() throws Exception + { + annotationArray(0); + } + + final int annotationArray(int pos) throws Exception + { + int num = ByteArray.readU16bit(info, pos); + return annotationArray(pos + 2, num); + } + + int annotationArray(int pos, int num) throws Exception + { + for (int i = 0; i < num; ++i) + pos = annotation(pos); + + return pos; + } + + final int annotation(int pos) throws Exception + { + int type = ByteArray.readU16bit(info, pos); + int numPairs = ByteArray.readU16bit(info, pos + 2); + return annotation(pos + 4, type, numPairs); + } + + int annotation(int pos, int type, int numPairs) throws Exception + { + for (int j = 0; j < numPairs; ++j) + pos = memberValuePair(pos); + + return pos; + } + + final int memberValuePair(int pos) throws Exception + { + int nameIndex = ByteArray.readU16bit(info, pos); + return memberValuePair(pos + 2, nameIndex); + } + + int memberValuePair(int pos, int nameIndex) throws Exception + { + return memberValue(pos); + } + + final int memberValue(int pos) throws Exception + { + int tag = info[pos] & 0xff; + if (tag == 'e') + { + int typeNameIndex = ByteArray.readU16bit(info, pos + 1); + int constNameIndex = ByteArray.readU16bit(info, pos + 3); + enumMemberValue(typeNameIndex, constNameIndex); + return pos + 5; + } + else if (tag == 'c') + { + int index = ByteArray.readU16bit(info, pos + 1); + classMemberValue(index); + return pos + 3; + } + else if (tag == '@') + return annotationMemberValue(pos + 1); + else if (tag == '[') + { + int num = ByteArray.readU16bit(info, pos + 1); + return arrayMemberValue(pos + 3, num); + } + else + { // primitive types or String. + int index = ByteArray.readU16bit(info, pos + 1); + constValueMember(tag, index); + return pos + 3; + } + } + + void constValueMember(int tag, int index) throws Exception + { + } + + void enumMemberValue(int typeNameIndex, int constNameIndex) + throws Exception + { + } + + void classMemberValue(int index) throws Exception + { + } + + int annotationMemberValue(int pos) throws Exception + { + return annotation(pos); + } + + int arrayMemberValue(int pos, int num) throws Exception + { + for (int i = 0; i < num; ++i) + { + pos = memberValue(pos); + } + + return pos; + } + } + + static class Copier extends Walker + { + ByteArrayOutputStream output; + AnnotationsWriter writer; + ConstPool srcPool, destPool; + Map classnames; + + /** + * Constructs a copier. This copier renames some class names + * into the new names specified by <code>map</code> when it copies + * an annotation attribute. + * + * @param info the source attribute. + * @param src the constant pool of the source class. + * @param dest the constant pool of the destination class. + * @param map pairs of replaced and substituted class names. + * It can be null. + */ + Copier(byte[] info, ConstPool src, ConstPool dest, Map map) + { + super(info); + output = new ByteArrayOutputStream(); + writer = new AnnotationsWriter(output, dest); + srcPool = src; + destPool = dest; + classnames = map; + } + + byte[] close() throws IOException + { + writer.close(); + return output.toByteArray(); + } + + void parameters(int numParam, int pos) throws Exception + { + writer.numParameters(numParam); + super.parameters(numParam, pos); + } + + int annotationArray(int pos, int num) throws Exception + { + writer.numAnnotations(num); + return super.annotationArray(pos, num); + } + + int annotation(int pos, int type, int numPairs) throws Exception + { + writer.annotation(copy(type), numPairs); + return super.annotation(pos, type, numPairs); + } + + int memberValuePair(int pos, int nameIndex) throws Exception + { + writer.memberValuePair(copy(nameIndex)); + return super.memberValuePair(pos, nameIndex); + } + + void constValueMember(int tag, int index) throws Exception + { + writer.constValueIndex(tag, copy(index)); + super.constValueMember(tag, index); + } + + void enumMemberValue(int typeNameIndex, int constNameIndex) + throws Exception + { + writer.enumConstValue(copy(typeNameIndex), copy(constNameIndex)); + super.enumMemberValue(typeNameIndex, constNameIndex); + } + + void classMemberValue(int index) throws Exception + { + writer.classInfoIndex(copy(index)); + super.classMemberValue(index); + } + + int annotationMemberValue(int pos) throws Exception + { + writer.annotationValue(); + return super.annotationMemberValue(pos); + } + + int arrayMemberValue(int pos, int num) throws Exception + { + writer.arrayValue(num); + return super.arrayMemberValue(pos, num); + } + + /** + * Copies a constant pool entry into the destination constant pool + * and returns the index of the copied entry. + * + * @param srcIndex the index of the copied entry into the source + * constant pool. + * @return the index of the copied item into the destination + * constant pool. + */ + int copy(int srcIndex) + { + return srcPool.copy(srcIndex, destPool, classnames); + } + } + + static class Parser extends Walker + { + ConstPool pool; + Annotation[][] allParams; // all parameters + Annotation[] allAnno; // all annotations + Annotation currentAnno; // current annotation + MemberValue memberValue; + + /** + * Constructs a parser. This parser constructs a parse tree of + * the annotations. + * + * @param info the attribute. + * @param src the constant pool. + */ + Parser(byte[] info, ConstPool cp) + { + super(info); + pool = cp; + } + + Annotation[][] parseParameters() throws Exception + { + parameters(); + return allParams; + } + + Annotation[] parseAnnotations() throws Exception + { + annotationArray(); + return allAnno; + } + + void parameters(int numParam, int pos) throws Exception + { + Annotation[][] params = new Annotation[numParam][]; + for (int i = 0; i < numParam; ++i) + { + pos = annotationArray(pos); + params[i] = allAnno; + } + + allParams = params; + } + + int annotationArray(int pos, int num) throws Exception + { + Annotation[] array = new Annotation[num]; + for (int i = 0; i < num; ++i) + { + pos = annotation(pos); + array[i] = currentAnno; + } + + allAnno = array; + return pos; + } + + int annotation(int pos, int type, int numPairs) throws Exception + { + currentAnno = new Annotation(type, pool); + return super.annotation(pos, type, numPairs); + } + + int memberValuePair(int pos, int nameIndex) throws Exception + { + pos = super.memberValuePair(pos, nameIndex); + currentAnno.addMemberValue(nameIndex, memberValue); + return pos; + } + + void constValueMember(int tag, int index) throws Exception + { + MemberValue m; + ConstPool cp = pool; + switch (tag) + { + case 'B': + m = new ByteMemberValue(index, cp); + break; + case 'C': + m = new CharMemberValue(index, cp); + break; + case 'D': + m = new DoubleMemberValue(index, cp); + break; + case 'F': + m = new FloatMemberValue(index, cp); + break; + case 'I': + m = new IntegerMemberValue(index, cp); + break; + case 'J': + m = new LongMemberValue(index, cp); + break; + case 'S': + m = new ShortMemberValue(index, cp); + break; + case 'Z': + m = new BooleanMemberValue(index, cp); + break; + case 's': + m = new StringMemberValue(index, cp); + break; + default : + throw new RuntimeException("unknown tag:" + tag); + } + + memberValue = m; + super.constValueMember(tag, index); + } + + void enumMemberValue(int typeNameIndex, int constNameIndex) + throws Exception + { + memberValue = new EnumMemberValue(typeNameIndex, + constNameIndex, pool); + super.enumMemberValue(typeNameIndex, constNameIndex); + } + + void classMemberValue(int index) throws Exception + { + memberValue = 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); + currentAnno = anno; + return pos; + } + + int arrayMemberValue(int pos, int num) throws Exception + { + ArrayMemberValue amv = new ArrayMemberValue(pool); + MemberValue[] elements = new MemberValue[num]; + for (int i = 0; i < num; ++i) + { + pos = memberValue(pos); + elements[i] = memberValue; + } + + amv.setValue(elements); + memberValue = amv; + return pos; + } + } } diff --git a/src/main/javassist/bytecode/MethodInfo.java b/src/main/javassist/bytecode/MethodInfo.java index 9e866578..b0744942 100644 --- a/src/main/javassist/bytecode/MethodInfo.java +++ b/src/main/javassist/bytecode/MethodInfo.java @@ -18,9 +18,9 @@ package javassist.bytecode; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.Map; -import java.util.List; import java.util.LinkedList; +import java.util.List; +import java.util.Map; /** * <code>method_info</code> structure. @@ -28,364 +28,395 @@ import java.util.LinkedList; * @see javassist.CtMethod#getMethodInfo() * @see javassist.CtConstructor#getMethodInfo() */ -public final class MethodInfo { - ConstPool constPool; - int accessFlags; - int name; - int descriptor; - LinkedList attribute; // may be null - - /** - * The name of constructors: <code><init></code>. - */ - public static final String nameInit = "<init>"; - - /** - * The name of class initializer (static initializer): - * <code><clinit></code>. - */ - public static final String nameClinit = "<clinit>"; - - private MethodInfo(ConstPool cp) { - constPool = cp; - attribute = null; - } - - /** - * Constructs a <code>method_info</code> structure. - * The initial value of <code>access_flags</code> is zero. - * - * @param cp a constant pool table - * @param methodname method name - * @param desc method descriptor - * - * @see Descriptor - */ - public MethodInfo(ConstPool cp, String methodname, String desc) { - this(cp); - accessFlags = 0; - name = cp.addUtf8Info(methodname); - descriptor = constPool.addUtf8Info(desc); - } - - MethodInfo(ConstPool cp, DataInputStream in) throws IOException { - this(cp); - read(in); - } - - /** - * Constructs a copy of <code>method_info</code> structure. - * Class names appearing in the source <code>method_info</code> - * are renamed according to <code>classnameMap</code>. - * - * <p>Note: only <code>Code</code> and <code>Exceptions</code> - * attributes are copied from the source. The other attributes - * are ignored. - * - * @param cp a constant pool table - * @param methodname a method name - * @param src a source <code>method_info</code> - * @param classnameMap specifies pairs of replaced and substituted - * name. - * @see Descriptor - */ - public MethodInfo(ConstPool cp, String methodname, MethodInfo src, - Map classnameMap) throws BadBytecode { - this(cp); - read(src, methodname, classnameMap); - } - - void prune(ConstPool cp) { - attribute = null; - name = cp.addUtf8Info(getName()); - descriptor = cp.addUtf8Info(getDescriptor()); - constPool = cp; - } - - /** - * Returns a method name. - */ - public String getName() { - return constPool.getUtf8Info(name); - } - - /** - * Sets a method name. - */ - public void setName(String newName) { - name = constPool.addUtf8Info(newName); - } - - /** - * Returns true if this is not a constructor or a class initializer - * (static initializer). - */ - public boolean isMethod() { - String n = getName(); - return !n.equals(nameInit) && !n.equals(nameClinit); - } - - /** - * Returns a constant pool table used by this method. - */ - public ConstPool getConstPool() { - return constPool; - } - - /** - * Returns true if this is a constructor. - */ - public boolean isConstructor() { - return getName().equals(nameInit); - } - - /** - * Returns true if this is a class initializer (static initializer). - */ - public boolean isStaticInitializer() { - return getName().equals(nameClinit); - } - - /** - * Returns access flags. - * - * @see AccessFlag - */ - public int getAccessFlags() { - return accessFlags; - } - - /** - * Sets access flags. - * - * @see AccessFlag - */ - public void setAccessFlags(int acc) { - accessFlags = acc; - } - - /** - * Returns a method descriptor. - * - * @see Descriptor - */ - public String getDescriptor() { - return constPool.getUtf8Info(descriptor); - } - - /** - * Sets a method descriptor. - * - * @see Descriptor - */ - public void setDescriptor(String desc) { - if (!desc.equals(getDescriptor())) - descriptor = constPool.addUtf8Info(desc); - } - - /** - * Returns all the attributes. - * A new element can be added to the returned list - * and an existing element can be removed from the list. - * - * @return a list of <code>AttributeInfo</code> objects. - * @see AttributeInfo - */ - public List getAttributes() { - if (attribute == null) - attribute = new LinkedList(); - - return attribute; - } - - /** - * Returns the attribute with the specified name. - * If it is not found, this method returns null. - * - * @param name attribute name - * @return an <code>AttributeInfo</code> object or null. - */ - public AttributeInfo getAttribute(String name) { - return AttributeInfo.lookup(attribute, name); - } - - /** - * Appends an attribute. If there is already an attribute with - * the same name, the new one substitutes for it. - */ - public void addAttribute(AttributeInfo info) { - if (attribute == null) - attribute = new LinkedList(); - - AttributeInfo.remove(attribute, info.getName()); - attribute.add(info); - } - - /** - * Returns an Exceptions attribute. - * - * @return an Exceptions attribute - * or null if it is not specified. - */ - public ExceptionsAttribute getExceptionsAttribute() { - AttributeInfo info - = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag); - return (ExceptionsAttribute)info; - } - - /** - * Returns a Code attribute. - * - * @return a Code attribute - * or null if it is not specified. - */ - public CodeAttribute getCodeAttribute() { - AttributeInfo info - = AttributeInfo.lookup(attribute, CodeAttribute.tag); - return (CodeAttribute)info; - } - - /** - * Removes an Exception attribute. - */ - public void removeExceptionsAttribute() { - AttributeInfo.remove(attribute, ExceptionsAttribute.tag); - } - - /** - * Adds an Exception attribute. - * - * <p>The added attribute must share the same constant pool table - * as this <code>method_info</code> structure. - */ - public void setExceptionsAttribute(ExceptionsAttribute cattr) { - removeExceptionsAttribute(); - if (attribute == null) - attribute = new LinkedList(); - - attribute.add(cattr); - } - - /** - * Removes a Code attribute. - */ - public void removeCodeAttribute() { - AttributeInfo.remove(attribute, CodeAttribute.tag); - } - - /** - * Adds a Code attribute. - * - * <p>The added attribute must share the same constant pool table - * as this <code>method_info</code> structure. - */ - public void setCodeAttribute(CodeAttribute cattr) { - removeCodeAttribute(); - if (attribute == null) - attribute = new LinkedList(); - - attribute.add(cattr); - } - - /** - * Returns the line number of the source line corresponding to the - * specified bytecode contained in this method. - * - * @param pos the position of the bytecode (>= 0). - * an index into the code array. - * @return -1 if this information is not available. - */ - public int getLineNumber(int pos) { - CodeAttribute ca = getCodeAttribute(); - if (ca == null) - return -1; - - LineNumberAttribute ainfo = - (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); - if (ainfo == null) - return -1; - - return ainfo.toLineNumber(pos); - } - - /** - * Changes a super constructor called by this constructor. - * - * <p>This method modifies a call to <code>super()</code>, - * which should be at the - * head of a constructor body, so that a constructor in a different - * super class is called. This method does not change actural - * parameters. Hence the new super class must have a constructor - * with the same signature as the original one. - * - * <p>This method should be called when the super class - * of the class declaring this method is changed. - * - * <p>This method does not perform anything unless this - * <code>MethodInfo</code> represents a constructor. - * - * @param superclass the new super class - */ - public void setSuperclass(String superclass) throws BadBytecode { - if (!isConstructor()) - return; - - CodeAttribute ca = getCodeAttribute(); - byte[] code = ca.getCode(); - CodeIterator iterator = ca.iterator(); - int pos = iterator.skipSuperConstructor(); - if (pos >= 0) { // not this() - ConstPool cp = constPool; - int mref = ByteArray.readU16bit(code, pos + 1); - int nt = cp.getMethodrefNameAndType(mref); - int sc = cp.addClassInfo(superclass); - int mref2 = cp.addMethodrefInfo(sc, nt); - ByteArray.write16bit(mref2, code, pos + 1); - } - } - - private void read(MethodInfo src, String methodname, Map classnames) - throws BadBytecode - { - ConstPool destCp = constPool; - accessFlags = src.accessFlags; - name = destCp.addUtf8Info(methodname); - - ConstPool srcCp = src.constPool; - String desc = srcCp.getUtf8Info(src.descriptor); - String desc2 = Descriptor.rename(desc, classnames); - descriptor = destCp.addUtf8Info(desc2); - - attribute = new LinkedList(); - ExceptionsAttribute eattr = src.getExceptionsAttribute(); - if (eattr != null) - attribute.add(eattr.copy(destCp, classnames)); - - CodeAttribute cattr = src.getCodeAttribute(); - if (cattr != null) - attribute.add(cattr.copy(destCp, classnames)); - } - - private void read(DataInputStream in) throws IOException { - accessFlags = in.readUnsignedShort(); - name = in.readUnsignedShort(); - descriptor = in.readUnsignedShort(); - int n = in.readUnsignedShort(); - attribute = new LinkedList(); - for (int i = 0; i < n; ++i) - attribute.add(AttributeInfo.read(constPool, in)); - } - - void write(DataOutputStream out) throws IOException { - out.writeShort(accessFlags); - out.writeShort(name); - out.writeShort(descriptor); - - if (attribute == null) - out.writeShort(0); - else { - out.writeShort(attribute.size()); - AttributeInfo.writeAll(attribute, out); - } - } +public final class MethodInfo +{ + ConstPool constPool; + int accessFlags; + int name; + int descriptor; + LinkedList attribute; // may be null + + /** + * The name of constructors: <code><init></code>. + */ + public static final String nameInit = "<init>"; + + /** + * The name of class initializer (static initializer): + * <code><clinit></code>. + */ + public static final String nameClinit = "<clinit>"; + + private MethodInfo(ConstPool cp) + { + constPool = cp; + attribute = null; + } + + /** + * Constructs a <code>method_info</code> structure. + * The initial value of <code>access_flags</code> is zero. + * + * @param cp a constant pool table + * @param methodname method name + * @param desc method descriptor + * @see Descriptor + */ + public MethodInfo(ConstPool cp, String methodname, String desc) + { + this(cp); + accessFlags = 0; + name = cp.addUtf8Info(methodname); + descriptor = constPool.addUtf8Info(desc); + } + + MethodInfo(ConstPool cp, DataInputStream in) throws IOException + { + this(cp); + read(in); + } + + /** + * Constructs a copy of <code>method_info</code> structure. + * Class names appearing in the source <code>method_info</code> + * are renamed according to <code>classnameMap</code>. + * <p/> + * <p>Note: only <code>Code</code> and <code>Exceptions</code> + * attributes are copied from the source. The other attributes + * are ignored. + * + * @param cp a constant pool table + * @param methodname a method name + * @param src a source <code>method_info</code> + * @param classnameMap specifies pairs of replaced and substituted + * name. + * @see Descriptor + */ + public MethodInfo(ConstPool cp, String methodname, MethodInfo src, + Map classnameMap) throws BadBytecode + { + this(cp); + read(src, methodname, classnameMap); + } + + void prune(ConstPool cp) + { + new Exception("****** pruned *****").printStackTrace(); + attribute = null; + name = cp.addUtf8Info(getName()); + descriptor = cp.addUtf8Info(getDescriptor()); + constPool = cp; + } + + /** + * Returns a method name. + */ + public String getName() + { + return constPool.getUtf8Info(name); + } + + /** + * Sets a method name. + */ + public void setName(String newName) + { + name = constPool.addUtf8Info(newName); + } + + /** + * Returns true if this is not a constructor or a class initializer + * (static initializer). + */ + public boolean isMethod() + { + String n = getName(); + return !n.equals(nameInit) && !n.equals(nameClinit); + } + + /** + * Returns a constant pool table used by this method. + */ + public ConstPool getConstPool() + { + return constPool; + } + + /** + * Returns true if this is a constructor. + */ + public boolean isConstructor() + { + return getName().equals(nameInit); + } + + /** + * Returns true if this is a class initializer (static initializer). + */ + public boolean isStaticInitializer() + { + return getName().equals(nameClinit); + } + + /** + * Returns access flags. + * + * @see AccessFlag + */ + public int getAccessFlags() + { + return accessFlags; + } + + /** + * Sets access flags. + * + * @see AccessFlag + */ + public void setAccessFlags(int acc) + { + accessFlags = acc; + } + + /** + * Returns a method descriptor. + * + * @see Descriptor + */ + public String getDescriptor() + { + return constPool.getUtf8Info(descriptor); + } + + /** + * Sets a method descriptor. + * + * @see Descriptor + */ + public void setDescriptor(String desc) + { + if (!desc.equals(getDescriptor())) + descriptor = constPool.addUtf8Info(desc); + } + + /** + * Returns all the attributes. + * A new element can be added to the returned list + * and an existing element can be removed from the list. + * + * @return a list of <code>AttributeInfo</code> objects. + * @see AttributeInfo + */ + public List getAttributes() + { + if (attribute == null) + attribute = new LinkedList(); + + return attribute; + } + + /** + * Returns the attribute with the specified name. + * If it is not found, this method returns null. + * + * @param name attribute name + * @return an <code>AttributeInfo</code> object or null. + */ + public AttributeInfo getAttribute(String name) + { + return AttributeInfo.lookup(attribute, name); + } + + /** + * Appends an attribute. If there is already an attribute with + * the same name, the new one substitutes for it. + */ + public void addAttribute(AttributeInfo info) + { + if (attribute == null) + attribute = new LinkedList(); + + AttributeInfo.remove(attribute, info.getName()); + attribute.add(info); + } + + /** + * Returns an Exceptions attribute. + * + * @return an Exceptions attribute + * or null if it is not specified. + */ + public ExceptionsAttribute getExceptionsAttribute() + { + AttributeInfo info + = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag); + return (ExceptionsAttribute) info; + } + + /** + * Returns a Code attribute. + * + * @return a Code attribute + * or null if it is not specified. + */ + public CodeAttribute getCodeAttribute() + { + AttributeInfo info + = AttributeInfo.lookup(attribute, CodeAttribute.tag); + return (CodeAttribute) info; + } + + /** + * Removes an Exception attribute. + */ + public void removeExceptionsAttribute() + { + AttributeInfo.remove(attribute, ExceptionsAttribute.tag); + } + + /** + * Adds an Exception attribute. + * <p/> + * <p>The added attribute must share the same constant pool table + * as this <code>method_info</code> structure. + */ + public void setExceptionsAttribute(ExceptionsAttribute cattr) + { + removeExceptionsAttribute(); + if (attribute == null) + attribute = new LinkedList(); + + attribute.add(cattr); + } + + /** + * Removes a Code attribute. + */ + public void removeCodeAttribute() + { + AttributeInfo.remove(attribute, CodeAttribute.tag); + } + + /** + * Adds a Code attribute. + * <p/> + * <p>The added attribute must share the same constant pool table + * as this <code>method_info</code> structure. + */ + public void setCodeAttribute(CodeAttribute cattr) + { + removeCodeAttribute(); + if (attribute == null) + attribute = new LinkedList(); + + attribute.add(cattr); + } + + /** + * Returns the line number of the source line corresponding to the + * specified bytecode contained in this method. + * + * @param pos the position of the bytecode (>= 0). + * an index into the code array. + * @return -1 if this information is not available. + */ + public int getLineNumber(int pos) + { + CodeAttribute ca = getCodeAttribute(); + if (ca == null) + return -1; + + LineNumberAttribute ainfo = + (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag); + if (ainfo == null) + return -1; + + return ainfo.toLineNumber(pos); + } + + /** + * Changes a super constructor called by this constructor. + * <p/> + * <p>This method modifies a call to <code>super()</code>, + * which should be at the + * head of a constructor body, so that a constructor in a different + * super class is called. This method does not change actural + * parameters. Hence the new super class must have a constructor + * with the same signature as the original one. + * <p/> + * <p>This method should be called when the super class + * of the class declaring this method is changed. + * <p/> + * <p>This method does not perform anything unless this + * <code>MethodInfo</code> represents a constructor. + * + * @param superclass the new super class + */ + public void setSuperclass(String superclass) throws BadBytecode + { + if (!isConstructor()) + return; + + CodeAttribute ca = getCodeAttribute(); + byte[] code = ca.getCode(); + CodeIterator iterator = ca.iterator(); + int pos = iterator.skipSuperConstructor(); + if (pos >= 0) + { // not this() + ConstPool cp = constPool; + int mref = ByteArray.readU16bit(code, pos + 1); + int nt = cp.getMethodrefNameAndType(mref); + int sc = cp.addClassInfo(superclass); + int mref2 = cp.addMethodrefInfo(sc, nt); + ByteArray.write16bit(mref2, code, pos + 1); + } + } + + private void read(MethodInfo src, String methodname, Map classnames) + throws BadBytecode + { + ConstPool destCp = constPool; + accessFlags = src.accessFlags; + name = destCp.addUtf8Info(methodname); + + ConstPool srcCp = src.constPool; + String desc = srcCp.getUtf8Info(src.descriptor); + String desc2 = Descriptor.rename(desc, classnames); + descriptor = destCp.addUtf8Info(desc2); + + attribute = new LinkedList(); + ExceptionsAttribute eattr = src.getExceptionsAttribute(); + if (eattr != null) + attribute.add(eattr.copy(destCp, classnames)); + + CodeAttribute cattr = src.getCodeAttribute(); + if (cattr != null) + attribute.add(cattr.copy(destCp, classnames)); + } + + private void read(DataInputStream in) throws IOException + { + accessFlags = in.readUnsignedShort(); + name = in.readUnsignedShort(); + descriptor = in.readUnsignedShort(); + int n = in.readUnsignedShort(); + attribute = new LinkedList(); + for (int i = 0; i < n; ++i) + attribute.add(AttributeInfo.read(constPool, in)); + } + + void write(DataOutputStream out) throws IOException + { + out.writeShort(accessFlags); + out.writeShort(name); + out.writeShort(descriptor); + + if (attribute == null) + out.writeShort(0); + else + { + out.writeShort(attribute.size()); + AttributeInfo.writeAll(attribute, out); + } + } } diff --git a/src/main/javassist/bytecode/annotation/ClassMemberValue.java b/src/main/javassist/bytecode/annotation/ClassMemberValue.java index 78a6217d..09a1075b 100644 --- a/src/main/javassist/bytecode/annotation/ClassMemberValue.java +++ b/src/main/javassist/bytecode/annotation/ClassMemberValue.java @@ -17,6 +17,7 @@ package javassist.bytecode.annotation; import javassist.bytecode.ConstPool; import javassist.bytecode.Descriptor; + import java.io.IOException; /** @@ -25,72 +26,83 @@ import java.io.IOException; * @author <a href="mailto:bill@jboss.org">Bill Burke</a> * @author Shigeru Chiba */ -public class ClassMemberValue extends MemberValue { - int valueIndex; +public class ClassMemberValue extends MemberValue +{ + int valueIndex; - /** - * Constructs a string constant value. The initial value is specified - * by the constant pool entry at the given index. - * - * @param index the index of a CONSTANT_Utf8_info structure. - */ - public ClassMemberValue(int index, ConstPool cp) { - super('c', cp); - this.valueIndex = index; - } + /** + * Constructs a string constant value. The initial value is specified + * by the constant pool entry at the given index. + * + * @param index the index of a CONSTANT_Utf8_info structure. + */ + public ClassMemberValue(int index, ConstPool cp) + { + super('c', cp); + this.valueIndex = index; + } - /** - * Constructs a string constant value. - * - * @param className the initial value. - */ - public ClassMemberValue(String className, ConstPool cp) { - super('c', cp); - setValue(className); - } + /** + * Constructs a string constant value. + * + * @param className the initial value. + */ + public ClassMemberValue(String className, ConstPool cp) + { + super('c', cp); + setValue(className); + } - /** - * Constructs a string constant value. - * The initial value is java.lang.Class. - */ - public ClassMemberValue(ConstPool cp) { - super('c', cp); - setValue("java.lang.Class"); - } + /** + * Constructs a string constant value. + * The initial value is java.lang.Class. + */ + public ClassMemberValue(ConstPool cp) + { + super('c', cp); + setValue("java.lang.Class"); + } - /** - * Obtains the value of the member. - * - * @return fully-qualified class name. - */ - public String getValue() { - return Descriptor.toClassName(cp.getUtf8Info(valueIndex)); - } + /** + * Obtains the value of the member. + * + * @return fully-qualified class name. + */ + public String getValue() + { + String v = cp.getUtf8Info(valueIndex); + return Descriptor.toClassName(v); + } - /** - * Sets the value of the member. - * - * @param newClassName fully-qualified class name. - */ - public void setValue(String newClassName) { - valueIndex = cp.addUtf8Info(Descriptor.of(newClassName)); - } + /** + * Sets the value of the member. + * + * @param newClassName fully-qualified class name. + */ + public void setValue(String newClassName) + { + String setTo = Descriptor.of(newClassName); + valueIndex = cp.addUtf8Info(setTo); + } - /** - * Obtains the string representation of this object. - */ - public String toString() { - return "<" + getValue() + " class>"; - } + /** + * Obtains the string representation of this object. + */ + public String toString() + { + return "<" + getValue() + " class>"; + } - void write(AnnotationsWriter writer) throws IOException { - writer.constValueIndex(getValue()); - } + void write(AnnotationsWriter writer) throws IOException + { + writer.classInfoIndex(valueIndex); + } - /** - * Accepts a visitor. - */ - public void accept(MemberValueVisitor visitor) { - visitor.visitClassMemberValue(this); - } + /** + * Accepts a visitor. + */ + public void accept(MemberValueVisitor visitor) + { + visitor.visitClassMemberValue(this); + } } |