/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.bytecode; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * Represents a java annotation. */ public class JavaAnnotation extends JAnnotation { static private final Logger log = Logger.getLogger(JavaAnnotation.class.getName()); private static Method _enumValueOf; private JavaClassLoader _loader; private HashMap<String,Object> _valueMap = new HashMap<String,Object>(8); private String _type; /** * Sets the class loader. */ public void setClassLoader(JavaClassLoader loader) { _loader = loader; } /** * Gets the class loader. */ public JavaClassLoader getClassLoader() { return _loader; } /** * Sets the type. */ public void setType(String type) { _type = type; } /** * Gets the type. */ public String getType() { return _type; } /** * Returns the value map. */ public HashMap<String,Object> getValueMap() { return _valueMap; } /** * Sets a value. */ public Object putValue(String key, Object value) { return _valueMap.put(key, value); } /** * Parses the annotation from an annotation block. */ static JavaAnnotation []parseAnnotations(InputStream is, ConstantPool cp, JavaClassLoader loader) throws IOException { int n = readShort(is); JavaAnnotation []annArray = new JavaAnnotation[n]; for (int i = 0; i < n; i++) { annArray[i] = parseAnnotation(is, cp, loader); } return annArray; } private static JavaAnnotation parseAnnotation(InputStream is, ConstantPool cp, JavaClassLoader loader) throws IOException { JavaAnnotation ann = new JavaAnnotation(); ann.setClassLoader(loader); int type = readShort(is); String typeName = cp.getUtf8(type).getValue(); if (typeName.endsWith(";")) typeName = typeName.substring(1, typeName.length() - 1).replace('/', '.'); ann.setType(typeName); try { Class aClass = Class.forName(typeName, false, Thread.currentThread().getContextClassLoader()); for (Method method : aClass.getDeclaredMethods()) { Object value = method.getDefaultValue(); if (value instanceof Class) { String className = ((Class) value).getName(); ann.putValue(method.getName(), loader.forName(className)); } else if (value != null) ann.putValue(method.getName(), value); } } catch (Exception e) { log.log(Level.FINER, e.toString(), e); } int nPairs = readShort(is); for (int j = 0; j < nPairs; j++) { int nameIndex = readShort(is); String name = cp.getUtf8(nameIndex).getValue(); Object value = parseElementValue(is, cp, loader); ann.putValue(name, value); } return ann; } private static Object parseElementValue(InputStream is, ConstantPool cp, JavaClassLoader loader) throws IOException { int tag = is.read(); switch (tag) { case 'Z': { int i = readShort(is); return cp.getInteger(i).getValue() == 0 ? Boolean.FALSE : Boolean.TRUE; } case 'B': { int i = readShort(is); return new Byte((byte) cp.getInteger(i).getValue()); } case 'S': { int i = readShort(is); return new Short((short) cp.getInteger(i).getValue()); } case 'I': { int i = readShort(is); return new Integer(cp.getInteger(i).getValue()); } case 'J': { int i = readShort(is); return new Long(cp.getLong(i).getValue()); } case 'F': { int i = readShort(is); return new Float(cp.getFloat(i).getValue()); } case 'D': { int i = readShort(is); return new Double(cp.getDouble(i).getValue()); } case 'C': { int i = readShort(is); return new Character((char) cp.getInteger(i).getValue()); } case 's': int i = readShort(is); return cp.getUtf8(i).getValue(); case 'e': { int type = readShort(is); int value = readShort(is); String enumClassName = cp.getUtf8(type).getValue(); enumClassName = enumClassName.substring(1, enumClassName.length() - 1); enumClassName = enumClassName.replace('/', '.'); try { Class enumClass = Class.forName(enumClassName, false, Thread.currentThread().getContextClassLoader()); String enumName = cp.getUtf8(value).getValue(); return _enumValueOf.invoke(null, enumClass, enumName); } catch (Exception e) { log.log(Level.FINE, e.toString(), e); return null; } } case 'c': // class { String className = cp.getUtf8(readShort(is)).getValue(); return loader.descriptorToClass(className, 0); } case '@': return parseAnnotation(is, cp, loader); case '[': { int n = readShort(is); Object []array = new Object[n]; for (int j = 0; j < n; j++) { array[j] = parseElementValue(is, cp, loader); } return array; } default: throw new IllegalStateException(); } } static int readShort(InputStream is) throws IOException { return (((is.read() & 0xff) << 8) + (is.read() & 0xff)); } static int readInt(InputStream is) throws IOException { return (((is.read() & 0xff) << 24) + ((is.read() & 0xff) << 16) + ((is.read() & 0xff) << 8) + ((is.read() & 0xff))); } public String toString() { return "JavaAnnotation[" + _type + "]"; } static { try { Class cl = Class.forName("java.lang.Enum"); _enumValueOf = cl.getMethod("valueOf", new Class[] { Class.class, String.class }); } catch (Throwable e) { e.printStackTrace(); } } }