001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.bytecode;
031:
032: import java.io.IOException;
033: import java.io.InputStream;
034: import java.lang.reflect.Method;
035: import java.util.HashMap;
036: import java.util.logging.Level;
037: import java.util.logging.Logger;
038:
039: /**
040: * Represents a java annotation.
041: */
042: public class JavaAnnotation extends JAnnotation {
043: static private final Logger log = Logger
044: .getLogger(JavaAnnotation.class.getName());
045:
046: private static Method _enumValueOf;
047:
048: private JavaClassLoader _loader;
049: private HashMap<String, Object> _valueMap = new HashMap<String, Object>(
050: 8);
051: private String _type;
052:
053: /**
054: * Sets the class loader.
055: */
056: public void setClassLoader(JavaClassLoader loader) {
057: _loader = loader;
058: }
059:
060: /**
061: * Gets the class loader.
062: */
063: public JavaClassLoader getClassLoader() {
064: return _loader;
065: }
066:
067: /**
068: * Sets the type.
069: */
070: public void setType(String type) {
071: _type = type;
072: }
073:
074: /**
075: * Gets the type.
076: */
077: public String getType() {
078: return _type;
079: }
080:
081: /**
082: * Returns the value map.
083: */
084: public HashMap<String, Object> getValueMap() {
085: return _valueMap;
086: }
087:
088: /**
089: * Sets a value.
090: */
091: public Object putValue(String key, Object value) {
092: return _valueMap.put(key, value);
093: }
094:
095: /**
096: * Parses the annotation from an annotation block.
097: */
098: static JavaAnnotation[] parseAnnotations(InputStream is,
099: ConstantPool cp, JavaClassLoader loader) throws IOException {
100: int n = readShort(is);
101:
102: JavaAnnotation[] annArray = new JavaAnnotation[n];
103:
104: for (int i = 0; i < n; i++) {
105: annArray[i] = parseAnnotation(is, cp, loader);
106: }
107:
108: return annArray;
109: }
110:
111: private static JavaAnnotation parseAnnotation(InputStream is,
112: ConstantPool cp, JavaClassLoader loader) throws IOException {
113: JavaAnnotation ann = new JavaAnnotation();
114: ann.setClassLoader(loader);
115:
116: int type = readShort(is);
117:
118: String typeName = cp.getUtf8(type).getValue();
119:
120: if (typeName.endsWith(";"))
121: typeName = typeName.substring(1, typeName.length() - 1)
122: .replace('/', '.');
123:
124: ann.setType(typeName);
125:
126: try {
127: Class aClass = Class.forName(typeName, false, Thread
128: .currentThread().getContextClassLoader());
129:
130: for (Method method : aClass.getDeclaredMethods()) {
131: Object value = method.getDefaultValue();
132:
133: if (value instanceof Class) {
134: String className = ((Class) value).getName();
135:
136: ann.putValue(method.getName(), loader
137: .forName(className));
138: } else if (value != null)
139: ann.putValue(method.getName(), value);
140: }
141: } catch (Exception e) {
142: log.log(Level.FINER, e.toString(), e);
143: }
144:
145: int nPairs = readShort(is);
146: for (int j = 0; j < nPairs; j++) {
147: int nameIndex = readShort(is);
148:
149: String name = cp.getUtf8(nameIndex).getValue();
150:
151: Object value = parseElementValue(is, cp, loader);
152:
153: ann.putValue(name, value);
154: }
155:
156: return ann;
157: }
158:
159: private static Object parseElementValue(InputStream is,
160: ConstantPool cp, JavaClassLoader loader) throws IOException {
161: int tag = is.read();
162:
163: switch (tag) {
164: case 'Z': {
165: int i = readShort(is);
166:
167: return cp.getInteger(i).getValue() == 0 ? Boolean.FALSE
168: : Boolean.TRUE;
169: }
170:
171: case 'B': {
172: int i = readShort(is);
173:
174: return new Byte((byte) cp.getInteger(i).getValue());
175: }
176:
177: case 'S': {
178: int i = readShort(is);
179:
180: return new Short((short) cp.getInteger(i).getValue());
181: }
182:
183: case 'I': {
184: int i = readShort(is);
185:
186: return new Integer(cp.getInteger(i).getValue());
187: }
188:
189: case 'J': {
190: int i = readShort(is);
191:
192: return new Long(cp.getLong(i).getValue());
193: }
194:
195: case 'F': {
196: int i = readShort(is);
197:
198: return new Float(cp.getFloat(i).getValue());
199: }
200:
201: case 'D': {
202: int i = readShort(is);
203:
204: return new Double(cp.getDouble(i).getValue());
205: }
206:
207: case 'C': {
208: int i = readShort(is);
209:
210: return new Character((char) cp.getInteger(i).getValue());
211: }
212:
213: case 's':
214: int i = readShort(is);
215: return cp.getUtf8(i).getValue();
216: case 'e': {
217: int type = readShort(is);
218: int value = readShort(is);
219: String enumClassName = cp.getUtf8(type).getValue();
220: enumClassName = enumClassName.substring(1, enumClassName
221: .length() - 1);
222: enumClassName = enumClassName.replace('/', '.');
223:
224: try {
225: Class enumClass = Class.forName(enumClassName, false,
226: Thread.currentThread().getContextClassLoader());
227: String enumName = cp.getUtf8(value).getValue();
228:
229: return _enumValueOf.invoke(null, enumClass, enumName);
230:
231: } catch (Exception e) {
232: log.log(Level.FINE, e.toString(), e);
233:
234: return null;
235: }
236: }
237: case 'c':
238: // class
239: {
240: String className = cp.getUtf8(readShort(is)).getValue();
241:
242: return loader.descriptorToClass(className, 0);
243: }
244: case '@':
245: return parseAnnotation(is, cp, loader);
246: case '[': {
247: int n = readShort(is);
248:
249: Object[] array = new Object[n];
250: for (int j = 0; j < n; j++) {
251: array[j] = parseElementValue(is, cp, loader);
252: }
253:
254: return array;
255: }
256: default:
257: throw new IllegalStateException();
258: }
259: }
260:
261: static int readShort(InputStream is) throws IOException {
262: return (((is.read() & 0xff) << 8) + (is.read() & 0xff));
263: }
264:
265: static int readInt(InputStream is) throws IOException {
266: return (((is.read() & 0xff) << 24) + ((is.read() & 0xff) << 16)
267: + ((is.read() & 0xff) << 8) + ((is.read() & 0xff)));
268: }
269:
270: public String toString() {
271: return "JavaAnnotation[" + _type + "]";
272: }
273:
274: static {
275: try {
276: Class cl = Class.forName("java.lang.Enum");
277: _enumValueOf = cl.getMethod("valueOf", new Class[] {
278: Class.class, String.class });
279: } catch (Throwable e) {
280: e.printStackTrace();
281: }
282: }
283: }
|