diff options
Diffstat (limited to 'src/main/javassist/tools/reflect/Metaobject.java')
-rw-r--r-- | src/main/javassist/tools/reflect/Metaobject.java | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/src/main/javassist/tools/reflect/Metaobject.java b/src/main/javassist/tools/reflect/Metaobject.java new file mode 100644 index 00000000..e89b5398 --- /dev/null +++ b/src/main/javassist/tools/reflect/Metaobject.java @@ -0,0 +1,236 @@ +/* + * Javassist, a Java-bytecode translator toolkit. + * Copyright (C) 1999-2005 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. + * + * 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 javassist.tools.reflect; + +import java.lang.reflect.Method; +import java.io.Serializable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * A runtime metaobject. + * + * <p>A <code>Metaobject</code> is created for + * every object at the base level. A different reflective object is + * associated with a different metaobject. + * + * <p>The metaobject intercepts method calls + * on the reflective object at the base-level. To change the behavior + * of the method calls, a subclass of <code>Metaobject</code> + * should be defined. + * + * <p>To obtain a metaobject, calls <code>_getMetaobject()</code> + * on a reflective object. For example, + * + * <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject(); + * </pre></ul> + * + * @see javassist.tools.reflect.ClassMetaobject + * @see javassist.tools.reflect.Metalevel + */ +public class Metaobject implements Serializable { + protected ClassMetaobject classmetaobject; + protected Metalevel baseobject; + protected Method[] methods; + + /** + * Constructs a <code>Metaobject</code>. The metaobject is + * constructed before the constructor is called on the base-level + * object. + * + * @param self the object that this metaobject is associated with. + * @param args the parameters passed to the constructor of + * <code>self</code>. + */ + public Metaobject(Object self, Object[] args) { + baseobject = (Metalevel)self; + classmetaobject = baseobject._getClass(); + methods = classmetaobject.getReflectiveMethods(); + } + + /** + * Constructs a <code>Metaobject</code> without initialization. + * If calling this constructor, a subclass should be responsible + * for initialization. + */ + protected Metaobject() { + baseobject = null; + classmetaobject = null; + methods = null; + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeObject(baseobject); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException + { + baseobject = (Metalevel)in.readObject(); + classmetaobject = baseobject._getClass(); + methods = classmetaobject.getReflectiveMethods(); + } + + /** + * Obtains the class metaobject associated with this metaobject. + * + * @see javassist.tools.reflect.ClassMetaobject + */ + public final ClassMetaobject getClassMetaobject() { + return classmetaobject; + } + + /** + * Obtains the object controlled by this metaobject. + */ + public final Object getObject() { + return baseobject; + } + + /** + * Changes the object controlled by this metaobject. + * + * @param self the object + */ + public final void setObject(Object self) { + baseobject = (Metalevel)self; + classmetaobject = baseobject._getClass(); + methods = classmetaobject.getReflectiveMethods(); + + // call _setMetaobject() after the metaobject is settled. + baseobject._setMetaobject(this); + } + + /** + * Returns the name of the method specified + * by <code>identifier</code>. + */ + public final String getMethodName(int identifier) { + String mname = methods[identifier].getName(); + int j = ClassMetaobject.methodPrefixLen; + for (;;) { + char c = mname.charAt(j++); + if (c < '0' || '9' < c) + break; + } + + return mname.substring(j); + } + + /** + * Returns an array of <code>Class</code> objects representing the + * formal parameter types of the method specified + * by <code>identifier</code>. + */ + public final Class[] getParameterTypes(int identifier) { + return methods[identifier].getParameterTypes(); + } + + /** + * Returns a <code>Class</code> objects representing the + * return type of the method specified by <code>identifier</code>. + */ + public final Class getReturnType(int identifier) { + return methods[identifier].getReturnType(); + } + + /** + * Is invoked when public fields of the base-level + * class are read and the runtime system intercepts it. + * This method simply returns the value of the field. + * + * <p>Every subclass of this class should redefine this method. + */ + public Object trapFieldRead(String name) { + Class jc = getClassMetaobject().getJavaClass(); + try { + return jc.getField(name).get(getObject()); + } + catch (NoSuchFieldException e) { + throw new RuntimeException(e.toString()); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e.toString()); + } + } + + /** + * Is invoked when public fields of the base-level + * class are modified and the runtime system intercepts it. + * This method simply sets the field to the given value. + * + * <p>Every subclass of this class should redefine this method. + */ + public void trapFieldWrite(String name, Object value) { + Class jc = getClassMetaobject().getJavaClass(); + try { + jc.getField(name).set(getObject(), value); + } + catch (NoSuchFieldException e) { + throw new RuntimeException(e.toString()); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e.toString()); + } + } + + /** + * Is invoked when base-level method invocation is intercepted. + * This method simply executes the intercepted method invocation + * with the original parameters and returns the resulting value. + * + * <p>Every subclass of this class should redefine this method. + * + * <p>Note: this method is not invoked if the base-level method + * is invoked by a constructor in the super class. For example, + * + * <ul><pre>abstract class A { + * abstract void initialize(); + * A() { + * initialize(); // not intercepted + * } + * } + * + * class B extends A { + * void initialize() { System.out.println("initialize()"); } + * B() { + * super(); + * initialize(); // intercepted + * } + * }</pre></ul> + * + * <p>if an instance of B is created, + * the invocation of initialize() in B is intercepted only once. + * The first invocation by the constructor in A is not intercepted. + * This is because the link between a base-level object and a + * metaobject is not created until the execution of a + * constructor of the super class finishes. + */ + public Object trapMethodcall(int identifier, Object[] args) + throws Throwable + { + try { + return methods[identifier].invoke(getObject(), args); + } + catch (java.lang.reflect.InvocationTargetException e) { + throw e.getTargetException(); + } + catch (java.lang.IllegalAccessException e) { + throw new CannotInvokeException(e); + } + } +} |