All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.tools.reflect.Reflection Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- 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,
 * or the Apache License Version 2.0.
 *
 * 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 com.feilong.lib.javassist.tools.reflect;

import com.feilong.lib.javassist.CannotCompileException;
import com.feilong.lib.javassist.ClassPool;
import com.feilong.lib.javassist.CodeConverter;
import com.feilong.lib.javassist.CtClass;
import com.feilong.lib.javassist.CtField;
import com.feilong.lib.javassist.CtMethod;
import com.feilong.lib.javassist.CtMethod.ConstParameter;
import com.feilong.lib.javassist.CtNewMethod;
import com.feilong.lib.javassist.Modifier;
import com.feilong.lib.javassist.NotFoundException;
import com.feilong.lib.javassist.Translator;
import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.ClassFile;
import com.feilong.lib.javassist.bytecode.MethodInfo;

/**
 * The class implementing the behavioral reflection mechanism.
 *
 * 

* If a class is reflective, * then all the method invocations on every * instance of that class are intercepted by the runtime * metaobject controlling that instance. The methods inherited from the * super classes are also intercepted except final methods. To intercept * a final method in a super class, that super class must be also reflective. * *

* To do this, the original class file representing a reflective class: * *

 * class Person{
 * 
 *     public int f(int i){
 *         return i + 1;
 *     }
 * 
 *     public int value;
 * }
 * 
* *

* is modified so that it represents a class: * *

 * class Person implements Metalevel {
 *   public int _original_f(int i) { return i + 1; }
 *   public int f(int i) { delegate to the metaobject }
 *
 *   public int value;
 *   public int _r_value() { read "value" }
 *   public void _w_value(int v) { write "value" }
 *
 *   public ClassMetaobject _getClass() { return a class metaobject }
 *   public Metaobject _getMetaobject() { return a metaobject }
 *   public void _setMetaobject(Metaobject m) { change a metaobject }
 * }
 * 
* * @see com.feilong.lib.javassist.tools.reflect.ClassMetaobject * @see com.feilong.lib.javassist.tools.reflect.Metaobject * @see com.feilong.lib.javassist.tools.reflect.Loader */ public class Reflection implements Translator{ static final String classobjectField = "_classobject"; static final String classobjectAccessor = "_getClass"; static final String metaobjectField = "_metaobject"; static final String metaobjectGetter = "_getMetaobject"; static final String metaobjectSetter = "_setMetaobject"; static final String readPrefix = "_r_"; static final String writePrefix = "_w_"; static final String metaobjectClassName = com.feilong.lib.javassist.tools.reflect.Metaobject.class.getName(); static final String classMetaobjectClassName = com.feilong.lib.javassist.tools.reflect.ClassMetaobject.class.getName(); protected CtMethod trapMethod, trapStaticMethod; protected CtMethod trapRead, trapWrite; protected CtClass[] readParam; protected ClassPool classPool; protected CodeConverter converter; private boolean isExcluded(String name){ return name.startsWith(ClassMetaobject.methodPrefix) || name.equals(classobjectAccessor) || name.equals(metaobjectSetter) || name.equals(metaobjectGetter) || name.startsWith(readPrefix) || name.startsWith(writePrefix); } /** * Constructs a new Reflection object. */ public Reflection(){ classPool = null; converter = new CodeConverter(); } /** * Initializes the object. */ @Override public void start(ClassPool pool) throws NotFoundException{ classPool = pool; String classname = "com.feilong.lib.javassist.tools.reflect.Sample"; try{ CtClass c = classPool.get(classname); rebuildClassFile(c.getClassFile()); trapMethod = c.getDeclaredMethod("trap"); trapStaticMethod = c.getDeclaredMethod("trapStatic"); trapRead = c.getDeclaredMethod("trapRead"); trapWrite = c.getDeclaredMethod("trapWrite"); readParam = new CtClass[] { classPool.get("java.lang.Object") }; }catch (NotFoundException e){ throw new RuntimeException(classname + " is not found or broken."); }catch (BadBytecode e){ throw new RuntimeException(classname + " is not found or broken."); } } /** * Inserts hooks for intercepting accesses to the fields declared * in reflective classes. */ @Override public void onLoad(ClassPool pool,String classname) throws CannotCompileException,NotFoundException{ CtClass clazz = pool.get(classname); clazz.instrument(converter); } /** * Produces a reflective class. * If the super class is also made reflective, it must be done * before the sub class. * * @param classname * the name of the reflective class * @param metaobject * the class name of metaobjects. * @param metaclass * the class name of the class metaobject. * @return false if the class is already reflective. * * @see com.feilong.lib.javassist.tools.reflect.ClassMetaobject */ public boolean makeReflective(String classname,String metaobject,String metaclass) throws CannotCompileException,NotFoundException{ return makeReflective(classPool.get(classname), classPool.get(metaobject), classPool.get(metaclass)); } /** * Produces a reflective class. * If the super class is also made reflective, it must be done * before the sub class. * * @param clazz * the reflective class. * @param metaobject * the class of metaobjects. * It must be a subclass of * Metaobject. * @param metaclass * the class of the class metaobject. * It must be a subclass of * ClassMetaobject. * @return false if the class is already reflective. * * @see com.feilong.lib.javassist.tools.reflect.ClassMetaobject */ public boolean makeReflective(Class clazz,Class metaobject,Class metaclass) throws CannotCompileException,NotFoundException{ return makeReflective(clazz.getName(), metaobject.getName(), metaclass.getName()); } /** * Produces a reflective class. It modifies the given * CtClass object and makes it reflective. * If the super class is also made reflective, it must be done * before the sub class. * * @param clazz * the reflective class. * @param metaobject * the class of metaobjects. * It must be a subclass of * Metaobject. * @param metaclass * the class of the class metaobject. * It must be a subclass of * ClassMetaobject. * @return false if the class is already reflective. * * @see com.feilong.lib.javassist.tools.reflect.ClassMetaobject */ public boolean makeReflective(CtClass clazz,CtClass metaobject,CtClass metaclass) throws CannotCompileException,CannotReflectException,NotFoundException{ if (clazz.isInterface()){ throw new CannotReflectException("Cannot reflect an interface: " + clazz.getName()); } if (clazz.subclassOf(classPool.get(classMetaobjectClassName))){ throw new CannotReflectException("Cannot reflect a subclass of ClassMetaobject: " + clazz.getName()); } if (clazz.subclassOf(classPool.get(metaobjectClassName))){ throw new CannotReflectException("Cannot reflect a subclass of Metaobject: " + clazz.getName()); } registerReflectiveClass(clazz); return modifyClassfile(clazz, metaobject, metaclass); } /** * Registers a reflective class. The field accesses to the instances * of this class are instrumented. */ private void registerReflectiveClass(CtClass clazz){ CtField[] fs = clazz.getDeclaredFields(); for (CtField f : fs){ int mod = f.getModifiers(); if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0){ String name = f.getName(); converter.replaceFieldRead(f, clazz, readPrefix + name); converter.replaceFieldWrite(f, clazz, writePrefix + name); } } } private boolean modifyClassfile(CtClass clazz,CtClass metaobject,CtClass metaclass) throws CannotCompileException,NotFoundException{ if (clazz.getAttribute("Reflective") != null){ return false; // this is already reflective. } clazz.setAttribute("Reflective", new byte[0]); CtClass mlevel = classPool.get(com.feilong.lib.javassist.tools.reflect.Metalevel.class.getName()); boolean addMeta = !clazz.subtypeOf(mlevel); if (addMeta){ clazz.addInterface(mlevel); } processMethods(clazz, addMeta); processFields(clazz); CtField ctField; if (addMeta){ ctField = new CtField(classPool.get(com.feilong.lib.javassist.tools.reflect.Metaobject.class.getName()), metaobjectField, clazz); ctField.setModifiers(Modifier.PROTECTED); clazz.addField(ctField, CtField.Initializer.byNewWithParams(metaobject)); clazz.addMethod(CtNewMethod.getter(metaobjectGetter, ctField)); clazz.addMethod(CtNewMethod.setter(metaobjectSetter, ctField)); } ctField = new CtField(classPool.get(com.feilong.lib.javassist.tools.reflect.ClassMetaobject.class.getName()), classobjectField, clazz); ctField.setModifiers(Modifier.PRIVATE | Modifier.STATIC); clazz.addField(ctField, CtField.Initializer.byNew(metaclass, new String[] { clazz.getName() })); clazz.addMethod(CtNewMethod.getter(classobjectAccessor, ctField)); return true; } private void processMethods(CtClass clazz,boolean dontSearch) throws CannotCompileException,NotFoundException{ CtMethod[] ms = clazz.getMethods(); for (int i = 0; i < ms.length; ++i){ CtMethod m = ms[i]; int mod = m.getModifiers(); if (Modifier.isPublic(mod) && !Modifier.isAbstract(mod)){ processMethods0(mod, clazz, m, i, dontSearch); } } } private void processMethods0(int mod,CtClass clazz,CtMethod m,int identifier,boolean dontSearch) throws CannotCompileException,NotFoundException{ CtMethod body; String name = m.getName(); if (isExcluded(name)){ return; // from a reflective class. } CtMethod ctMethod; if (m.getDeclaringClass() == clazz){ if (Modifier.isNative(mod)){ return; } ctMethod = m; if (Modifier.isFinal(mod)){ mod &= ~Modifier.FINAL; ctMethod.setModifiers(mod); } }else{ if (Modifier.isFinal(mod)){ return; } mod &= ~Modifier.NATIVE; ctMethod = CtNewMethod.delegator(findOriginal(m, dontSearch), clazz); ctMethod.setModifiers(mod); clazz.addMethod(ctMethod); } ctMethod.setName(ClassMetaobject.methodPrefix + identifier + "_" + name); if (Modifier.isStatic(mod)){ body = trapStaticMethod; }else{ body = trapMethod; } CtMethod wmethod = CtNewMethod.wrapped( m.getReturnType(), name, m.getParameterTypes(), m.getExceptionTypes(), body, ConstParameter.integer(identifier), clazz); wmethod.setModifiers(mod); clazz.addMethod(wmethod); } private CtMethod findOriginal(CtMethod m,boolean dontSearch) throws NotFoundException{ if (dontSearch){ return m; } String name = m.getName(); CtMethod[] ms = m.getDeclaringClass().getDeclaredMethods(); for (CtMethod element : ms){ String orgName = element.getName(); if (orgName.endsWith(name) && orgName.startsWith(ClassMetaobject.methodPrefix) && element.getSignature().equals(m.getSignature())){ return element; } } return m; } private void processFields(CtClass clazz) throws CannotCompileException,NotFoundException{ CtField[] fs = clazz.getDeclaredFields(); for (CtField f : fs){ int mod = f.getModifiers(); if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0){ mod |= Modifier.STATIC; String name = f.getName(); CtClass ftype = f.getType(); CtMethod wmethod = CtNewMethod .wrapped(ftype, readPrefix + name, readParam, null, trapRead, ConstParameter.string(name), clazz); wmethod.setModifiers(mod); clazz.addMethod(wmethod); CtClass[] writeParam = new CtClass[2]; writeParam[0] = classPool.get("java.lang.Object"); writeParam[1] = ftype; wmethod = CtNewMethod.wrapped( CtClass.voidType, writePrefix + name, writeParam, null, trapWrite, ConstParameter.string(name), clazz); wmethod.setModifiers(mod); clazz.addMethod(wmethod); } } } public void rebuildClassFile(ClassFile cf) throws BadBytecode{ if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_6){ return; } for (MethodInfo mi : cf.getMethods()){ mi.rebuildStackMap(classPool); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy