169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.tools.reflect; 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Method; 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.Serializable; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.IOException; 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.ObjectInputStream; 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.ObjectOutputStream; 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A runtime metaobject. 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>A <code>Metaobject</code> is created for 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * every object at the base level. A different reflective object is 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * associated with a different metaobject. 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>The metaobject intercepts method calls 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * on the reflective object at the base-level. To change the behavior 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * of the method calls, a subclass of <code>Metaobject</code> 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * should be defined. 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>To obtain a metaobject, calls <code>_getMetaobject()</code> 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * on a reflective object. For example, 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject(); 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul> 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.ClassMetaobject 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.Metalevel 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Metaobject implements Serializable { 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected ClassMetaobject classmetaobject; 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected Metalevel baseobject; 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected Method[] methods; 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Constructs a <code>Metaobject</code>. The metaobject is 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * constructed before the constructor is called on the base-level 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * object. 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param self the object that this metaobject is associated with. 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param args the parameters passed to the constructor of 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>self</code>. 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Metaobject(Object self, Object[] args) { 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal baseobject = (Metalevel)self; 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal classmetaobject = baseobject._getClass(); 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal methods = classmetaobject.getReflectiveMethods(); 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Constructs a <code>Metaobject</code> without initialization. 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If calling this constructor, a subclass should be responsible 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for initialization. 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected Metaobject() { 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal baseobject = null; 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal classmetaobject = null; 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal methods = null; 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void writeObject(ObjectOutputStream out) throws IOException { 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal out.writeObject(baseobject); 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void readObject(ObjectInputStream in) 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws IOException, ClassNotFoundException 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal baseobject = (Metalevel)in.readObject(); 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal classmetaobject = baseobject._getClass(); 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal methods = classmetaobject.getReflectiveMethods(); 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Obtains the class metaobject associated with this metaobject. 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.ClassMetaobject 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public final ClassMetaobject getClassMetaobject() { 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return classmetaobject; 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Obtains the object controlled by this metaobject. 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public final Object getObject() { 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return baseobject; 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Changes the object controlled by this metaobject. 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param self the object 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public final void setObject(Object self) { 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal baseobject = (Metalevel)self; 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal classmetaobject = baseobject._getClass(); 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal methods = classmetaobject.getReflectiveMethods(); 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // call _setMetaobject() after the metaobject is settled. 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal baseobject._setMetaobject(this); 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the name of the method specified 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * by <code>identifier</code>. 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public final String getMethodName(int identifier) { 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String mname = methods[identifier].getName(); 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int j = ClassMetaobject.methodPrefixLen; 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (;;) { 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal char c = mname.charAt(j++); 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (c < '0' || '9' < c) 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal break; 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return mname.substring(j); 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns an array of <code>Class</code> objects representing the 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * formal parameter types of the method specified 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * by <code>identifier</code>. 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public final Class[] getParameterTypes(int identifier) { 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return methods[identifier].getParameterTypes(); 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns a <code>Class</code> objects representing the 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * return type of the method specified by <code>identifier</code>. 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public final Class getReturnType(int identifier) { 14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return methods[identifier].getReturnType(); 14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Is invoked when public fields of the base-level 15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class are read and the runtime system intercepts it. 15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This method simply returns the value of the field. 15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Every subclass of this class should redefine this method. 15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Object trapFieldRead(String name) { 15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Class jc = getClassMetaobject().getJavaClass(); 16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return jc.getField(name).get(getObject()); 16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (NoSuchFieldException e) { 16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e.toString()); 16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (IllegalAccessException e) { 16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e.toString()); 16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Is invoked when public fields of the base-level 17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class are modified and the runtime system intercepts it. 17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This method simply sets the field to the given value. 17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Every subclass of this class should redefine this method. 17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void trapFieldWrite(String name, Object value) { 17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Class jc = getClassMetaobject().getJavaClass(); 18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal jc.getField(name).set(getObject(), value); 18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (NoSuchFieldException e) { 18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e.toString()); 18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (IllegalAccessException e) { 18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e.toString()); 18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Is invoked when base-level method invocation is intercepted. 19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This method simply executes the intercepted method invocation 19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with the original parameters and returns the resulting value. 19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Every subclass of this class should redefine this method. 19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Note: this method is not invoked if the base-level method 19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is invoked by a constructor in the super class. For example, 20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>abstract class A { 20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * abstract void initialize(); 20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A() { 20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * initialize(); // not intercepted 20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * } 20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * } 20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class B extends A { 20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * void initialize() { System.out.println("initialize()"); } 21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * B() { 21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * super(); 21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * initialize(); // intercepted 21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * } 21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * }</pre></ul> 21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>if an instance of B is created, 21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the invocation of initialize() in B is intercepted only once. 21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The first invocation by the constructor in A is not intercepted. 21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This is because the link between a base-level object and a 22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * metaobject is not created until the execution of a 22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * constructor of the super class finishes. 22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Object trapMethodcall(int identifier, Object[] args) 22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws Throwable 22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return methods[identifier].invoke(getObject(), args); 22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (java.lang.reflect.InvocationTargetException e) { 23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw e.getTargetException(); 23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (java.lang.IllegalAccessException e) { 23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new CannotInvokeException(e); 23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 237