Home | History | Annotate | Download | only in reflect
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.tools.reflect;
     17 
     18 import java.lang.reflect.Method;
     19 import java.io.Serializable;
     20 import java.io.IOException;
     21 import java.io.ObjectInputStream;
     22 import java.io.ObjectOutputStream;
     23 
     24 /**
     25  * A runtime metaobject.
     26  *
     27  * <p>A <code>Metaobject</code> is created for
     28  * every object at the base level.  A different reflective object is
     29  * associated with a different metaobject.
     30  *
     31  * <p>The metaobject intercepts method calls
     32  * on the reflective object at the base-level.  To change the behavior
     33  * of the method calls, a subclass of <code>Metaobject</code>
     34  * should be defined.
     35  *
     36  * <p>To obtain a metaobject, calls <code>_getMetaobject()</code>
     37  * on a reflective object.  For example,
     38  *
     39  * <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject();
     40  * </pre></ul>
     41  *
     42  * @see javassist.tools.reflect.ClassMetaobject
     43  * @see javassist.tools.reflect.Metalevel
     44  */
     45 public class Metaobject implements Serializable {
     46     protected ClassMetaobject classmetaobject;
     47     protected Metalevel baseobject;
     48     protected Method[] methods;
     49 
     50     /**
     51      * Constructs a <code>Metaobject</code>.  The metaobject is
     52      * constructed before the constructor is called on the base-level
     53      * object.
     54      *
     55      * @param self      the object that this metaobject is associated with.
     56      * @param args      the parameters passed to the constructor of
     57      *                  <code>self</code>.
     58      */
     59     public Metaobject(Object self, Object[] args) {
     60         baseobject = (Metalevel)self;
     61         classmetaobject = baseobject._getClass();
     62         methods = classmetaobject.getReflectiveMethods();
     63     }
     64 
     65     /**
     66      * Constructs a <code>Metaobject</code> without initialization.
     67      * If calling this constructor, a subclass should be responsible
     68      * for initialization.
     69      */
     70     protected Metaobject() {
     71         baseobject = null;
     72         classmetaobject = null;
     73         methods = null;
     74     }
     75 
     76     private void writeObject(ObjectOutputStream out) throws IOException {
     77         out.writeObject(baseobject);
     78     }
     79 
     80     private void readObject(ObjectInputStream in)
     81         throws IOException, ClassNotFoundException
     82     {
     83         baseobject = (Metalevel)in.readObject();
     84         classmetaobject = baseobject._getClass();
     85         methods = classmetaobject.getReflectiveMethods();
     86     }
     87 
     88     /**
     89      * Obtains the class metaobject associated with this metaobject.
     90      *
     91      * @see javassist.tools.reflect.ClassMetaobject
     92      */
     93     public final ClassMetaobject getClassMetaobject() {
     94         return classmetaobject;
     95     }
     96 
     97     /**
     98      * Obtains the object controlled by this metaobject.
     99      */
    100     public final Object getObject() {
    101         return baseobject;
    102     }
    103 
    104     /**
    105      * Changes the object controlled by this metaobject.
    106      *
    107      * @param self      the object
    108      */
    109     public final void setObject(Object self) {
    110         baseobject = (Metalevel)self;
    111         classmetaobject = baseobject._getClass();
    112         methods = classmetaobject.getReflectiveMethods();
    113 
    114         // call _setMetaobject() after the metaobject is settled.
    115         baseobject._setMetaobject(this);
    116     }
    117 
    118     /**
    119      * Returns the name of the method specified
    120      * by <code>identifier</code>.
    121      */
    122     public final String getMethodName(int identifier) {
    123         String mname = methods[identifier].getName();
    124         int j = ClassMetaobject.methodPrefixLen;
    125         for (;;) {
    126             char c = mname.charAt(j++);
    127             if (c < '0' || '9' < c)
    128                 break;
    129         }
    130 
    131         return mname.substring(j);
    132     }
    133 
    134     /**
    135      * Returns an array of <code>Class</code> objects representing the
    136      * formal parameter types of the method specified
    137      * by <code>identifier</code>.
    138      */
    139     public final Class[] getParameterTypes(int identifier) {
    140         return methods[identifier].getParameterTypes();
    141     }
    142 
    143     /**
    144      * Returns a <code>Class</code> objects representing the
    145      * return type of the method specified by <code>identifier</code>.
    146      */
    147     public final Class getReturnType(int identifier) {
    148         return methods[identifier].getReturnType();
    149     }
    150 
    151     /**
    152      * Is invoked when public fields of the base-level
    153      * class are read and the runtime system intercepts it.
    154      * This method simply returns the value of the field.
    155      *
    156      * <p>Every subclass of this class should redefine this method.
    157      */
    158     public Object trapFieldRead(String name) {
    159         Class jc = getClassMetaobject().getJavaClass();
    160         try {
    161             return jc.getField(name).get(getObject());
    162         }
    163         catch (NoSuchFieldException e) {
    164             throw new RuntimeException(e.toString());
    165         }
    166         catch (IllegalAccessException e) {
    167             throw new RuntimeException(e.toString());
    168         }
    169     }
    170 
    171     /**
    172      * Is invoked when public fields of the base-level
    173      * class are modified and the runtime system intercepts it.
    174      * This method simply sets the field to the given value.
    175      *
    176      * <p>Every subclass of this class should redefine this method.
    177      */
    178     public void trapFieldWrite(String name, Object value) {
    179         Class jc = getClassMetaobject().getJavaClass();
    180         try {
    181             jc.getField(name).set(getObject(), value);
    182         }
    183         catch (NoSuchFieldException e) {
    184             throw new RuntimeException(e.toString());
    185         }
    186         catch (IllegalAccessException e) {
    187             throw new RuntimeException(e.toString());
    188         }
    189     }
    190 
    191     /**
    192      * Is invoked when base-level method invocation is intercepted.
    193      * This method simply executes the intercepted method invocation
    194      * with the original parameters and returns the resulting value.
    195      *
    196      * <p>Every subclass of this class should redefine this method.
    197      *
    198      * <p>Note: this method is not invoked if the base-level method
    199      * is invoked by a constructor in the super class.  For example,
    200      *
    201      * <ul><pre>abstract class A {
    202      *   abstract void initialize();
    203      *   A() {
    204      *       initialize();    // not intercepted
    205      *   }
    206      * }
    207      *
    208      * class B extends A {
    209      *   void initialize() { System.out.println("initialize()"); }
    210      *   B() {
    211      *       super();
    212      *       initialize();    // intercepted
    213      *   }
    214      * }</pre></ul>
    215      *
    216      * <p>if an instance of B is created,
    217      * the invocation of initialize() in B is intercepted only once.
    218      * The first invocation by the constructor in A is not intercepted.
    219      * This is because the link between a base-level object and a
    220      * metaobject is not created until the execution of a
    221      * constructor of the super class finishes.
    222      */
    223     public Object trapMethodcall(int identifier, Object[] args)
    224         throws Throwable
    225     {
    226         try {
    227             return methods[identifier].invoke(getObject(), args);
    228         }
    229         catch (java.lang.reflect.InvocationTargetException e) {
    230             throw e.getTargetException();
    231         }
    232         catch (java.lang.IllegalAccessException e) {
    233             throw new CannotInvokeException(e);
    234         }
    235     }
    236 }
    237