001: /*******************************************************************************************
002: * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
003: * http://backport175.codehaus.org *
004: * --------------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of Apache License Version 2.0 *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: *******************************************************************************************/package com.tc.backport175.bytecode;
008:
009: import com.tc.backport175.ReaderException;
010: import com.tc.backport175.bytecode.AnnotationElement.Annotation;
011:
012: import com.tc.asm.AnnotationVisitor;
013: import com.tc.asm.ClassReader;
014: import com.tc.asm.MethodVisitor;
015: import com.tc.asm.commons.EmptyVisitor;
016:
017: import java.util.Map;
018: import java.util.WeakHashMap;
019:
020: /**
021: * Container for default value of the annotations
022: * <p/>
023: * As per spec, default values are "unnamed" annotation on the element method of the annotation interface.
024: *
025: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
026: */
027: class AnnotationDefaults {
028:
029: /**
030: * Cache of default values, key is annotationClassKey, value is Annotation whose elements are named according
031: * to the element name which have a default value. Element without default value are thus not present in the Annotation.
032: */
033: private static Map s_annotationDefaults = new WeakHashMap();
034:
035: /**
036: * Retrieve (create if not in cache) the annotation defaults
037: *
038: * @param annotationClassName
039: * @param loader
040: * @return
041: */
042: public static AnnotationElement.Annotation getDefaults(
043: final String annotationClassName, final ClassLoader loader) {
044: AnnotationReader.ClassKey key = new AnnotationReader.ClassKey(
045: annotationClassName, loader);
046: AnnotationElement.Annotation defaults = (AnnotationElement.Annotation) s_annotationDefaults
047: .get(key);
048: if (defaults == null) {
049: final AnnotationElement.Annotation newDefaults = new AnnotationElement.Annotation(
050: annotationClassName);
051: final byte[] bytes;
052: try {
053: bytes = AnnotationReader.getBytecodeFor(
054: annotationClassName, loader);
055: } catch (Exception e) {
056: throw new ReaderException(
057: "could not retrieve the bytecode from the bytecode provider for class ["
058: + annotationClassName + "]", e);
059: }
060: ClassReader cr = new ClassReader(bytes);
061: cr.accept(new AnnotationDefaultsClassVisitor(newDefaults,
062: loader), //
063: ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE
064: | ClassReader.SKIP_FRAMES);
065: defaults = newDefaults;
066: s_annotationDefaults.put(key, newDefaults);
067: }
068: return defaults;
069: }
070:
071: static final class AnnotationDefaultsClassVisitor extends
072: EmptyVisitor {
073: private final AnnotationElement.Annotation defaults;
074: private final ClassLoader loader;
075:
076: AnnotationDefaultsClassVisitor(
077: AnnotationElement.Annotation defaults,
078: ClassLoader loader) {
079: this .defaults = defaults;
080: this .loader = loader;
081: }
082:
083: public MethodVisitor visitMethod(int access, final String name,
084: String desc, String signature, String[] exceptions) {
085: return new AnnotationDefaultsMethodVisitor(name, defaults,
086: loader);
087: }
088: }
089:
090: static final class AnnotationDefaultsMethodVisitor extends
091: EmptyVisitor {
092: private final String name;
093: private final Annotation defaults;
094: private final ClassLoader loader;
095:
096: AnnotationDefaultsMethodVisitor(String name,
097: Annotation defaults, ClassLoader loader) {
098: this .name = name;
099: this .defaults = defaults;
100: this .loader = loader;
101: }
102:
103: public AnnotationVisitor visitAnnotationDefault() {
104: return new DefaultAnnotationBuilderVisitor(defaults, name,
105: loader);
106: }
107: }
108:
109: /**
110: * Read the default value of annotation element
111: * Behave like a regular annotation visitor except that the name is force to the element name (else null in bytecode)
112: *
113: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
114: */
115: static class DefaultAnnotationBuilderVisitor extends
116: AnnotationReader.AnnotationBuilderVisitor {
117:
118: private String m_methodName;
119:
120: DefaultAnnotationBuilderVisitor(
121: final AnnotationElement.NestedAnnotationElement annotation,
122: String methodName, ClassLoader loader) {
123: super (annotation, loader, null);
124: m_methodName = methodName;
125: }
126:
127: public void visit(String name, Object value) {
128: super .visit(m_methodName, value);
129: }
130:
131: public void visitEnum(String name, String desc, String value) {
132: super .visitEnum(m_methodName, desc, value);
133: }
134:
135: public AnnotationVisitor visitAnnotation(String name,
136: String desc) {
137: return super .visitAnnotation(m_methodName, desc);
138: }
139:
140: public AnnotationVisitor visitArray(String name) {
141: return super .visitArray(m_methodName);
142: }
143:
144: }
145:
146: public static void refresh(AnnotationReader.ClassKey key) {
147: AnnotationElement.Annotation defaults = (AnnotationElement.Annotation) s_annotationDefaults
148: .get(key);
149: if (defaults != null) {
150: s_annotationDefaults.remove(key);
151: }
152: }
153: }
|