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 javassist.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtMethod.ConstParameter;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The class implementing the behavioral reflection mechanism.
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>If a class is reflective,
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * then all the method invocations on every
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instance of that class are intercepted by the runtime
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * metaobject controlling that instance.  The methods inherited from the
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * super classes are also intercepted except final methods.  To intercept
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * a final method in a super class, that super class must be also reflective.
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>To do this, the original class file representing a reflective class:
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class Person {
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public int f(int i) { return i + 1; }
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public int value;
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * }
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>is modified so that it represents a class:
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class Person implements Metalevel {
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public int _original_f(int i) { return i + 1; }
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public int f(int i) { <i>delegate to the metaobject</i> }
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public int value;
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public int _r_value() { <i>read "value"</i> }
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public void _w_value(int v) { <i>write "value"</i> }
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public ClassMetaobject _getClass() { <i>return a class metaobject</i> }
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public Metaobject _getMetaobject() { <i>return a metaobject</i> }
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *   public void _setMetaobject(Metaobject m) { <i>change a metaobject</i> }
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * }
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.ClassMetaobject
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.Metaobject
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.Loader
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.reflect.Compiler
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Reflection implements Translator {
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String classobjectField = "_classobject";
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String classobjectAccessor = "_getClass";
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String metaobjectField = "_metaobject";
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String metaobjectGetter = "_getMetaobject";
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String metaobjectSetter = "_setMetaobject";
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String readPrefix = "_r_";
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String writePrefix = "_w_";
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String metaobjectClassName = "javassist.tools.reflect.Metaobject";
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static final String classMetaobjectClassName
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        = "javassist.tools.reflect.ClassMetaobject";
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected CtMethod trapMethod, trapStaticMethod;
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected CtMethod trapRead, trapWrite;
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected CtClass[] readParam;
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected ClassPool classPool;
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected CodeConverter converter;
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean isExcluded(String name) {
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return name.startsWith(ClassMetaobject.methodPrefix)
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            || name.equals(classobjectAccessor)
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            || name.equals(metaobjectSetter)
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            || name.equals(metaobjectGetter)
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            || name.startsWith(readPrefix)
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            || name.startsWith(writePrefix);
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a new <code>Reflection</code> object.
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Reflection() {
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classPool = null;
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        converter = new CodeConverter();
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Initializes the object.
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void start(ClassPool pool) throws NotFoundException {
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classPool = pool;
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        final String msg
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            = "javassist.tools.reflect.Sample is not found or broken.";
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtClass c = classPool.get("javassist.tools.reflect.Sample");
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            trapMethod = c.getDeclaredMethod("trap");
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            trapStaticMethod = c.getDeclaredMethod("trapStatic");
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            trapRead = c.getDeclaredMethod("trapRead");
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            trapWrite = c.getDeclaredMethod("trapWrite");
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            readParam
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                = new CtClass[] { classPool.get("java.lang.Object") };
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (NotFoundException e) {
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(msg);
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Inserts hooks for intercepting accesses to the fields declared
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * in reflective classes.
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void onLoad(ClassPool pool, String classname)
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, NotFoundException
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtClass clazz = pool.get(classname);
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clazz.instrument(converter);
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Produces a reflective class.
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If the super class is also made reflective, it must be done
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * before the sub class.
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param classname         the name of the reflective class
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param metaobject        the class name of metaobjects.
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param metaclass         the class name of the class metaobject.
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return <code>false</code>       if the class is already reflective.
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.reflect.Metaobject
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.reflect.ClassMetaobject
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean makeReflective(String classname,
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  String metaobject, String metaclass)
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, NotFoundException
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return makeReflective(classPool.get(classname),
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                              classPool.get(metaobject),
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                              classPool.get(metaclass));
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Produces a reflective class.
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If the super class is also made reflective, it must be done
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * before the sub class.
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param clazz             the reflective class.
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param metaobject        the class of metaobjects.
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          It must be a subclass of
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          <code>Metaobject</code>.
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param metaclass         the class of the class metaobject.
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          It must be a subclass of
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          <code>ClassMetaobject</code>.
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return <code>false</code>       if the class is already reflective.
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.reflect.Metaobject
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.reflect.ClassMetaobject
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean makeReflective(Class clazz,
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  Class metaobject, Class metaclass)
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, NotFoundException
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return makeReflective(clazz.getName(), metaobject.getName(),
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                              metaclass.getName());
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Produces a reflective class.  It modifies the given
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>CtClass</code> object and makes it reflective.
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If the super class is also made reflective, it must be done
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * before the sub class.
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param clazz             the reflective class.
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param metaobject        the class of metaobjects.
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          It must be a subclass of
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          <code>Metaobject</code>.
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param metaclass         the class of the class metaobject.
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          It must be a subclass of
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          <code>ClassMetaobject</code>.
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return <code>false</code>       if the class is already reflective.
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.reflect.Metaobject
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.reflect.ClassMetaobject
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean makeReflective(CtClass clazz,
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  CtClass metaobject, CtClass metaclass)
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, CannotReflectException,
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal               NotFoundException
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (clazz.isInterface())
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotReflectException(
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    "Cannot reflect an interface: " + clazz.getName());
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (clazz.subclassOf(classPool.get(classMetaobjectClassName)))
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotReflectException(
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                "Cannot reflect a subclass of ClassMetaobject: "
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                + clazz.getName());
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (clazz.subclassOf(classPool.get(metaobjectClassName)))
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotReflectException(
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                "Cannot reflect a subclass of Metaobject: "
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                + clazz.getName());
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        registerReflectiveClass(clazz);
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return modifyClassfile(clazz, metaobject, metaclass);
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Registers a reflective class.  The field accesses to the instances
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * of this class are instrumented.
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void registerReflectiveClass(CtClass clazz) {
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtField[] fs = clazz.getDeclaredFields();
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < fs.length; ++i) {
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtField f = fs[i];
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mod = f.getModifiers();
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                String name = f.getName();
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                converter.replaceFieldRead(f, clazz, readPrefix + name);
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                converter.replaceFieldWrite(f, clazz, writePrefix + name);
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean modifyClassfile(CtClass clazz, CtClass metaobject,
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                    CtClass metaclass)
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, NotFoundException
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (clazz.getAttribute("Reflective") != null)
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;       // this is already reflective.
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz.setAttribute("Reflective", new byte[0]);
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtClass mlevel = classPool.get("javassist.tools.reflect.Metalevel");
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        boolean addMeta = !clazz.subtypeOf(mlevel);
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (addMeta)
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz.addInterface(mlevel);
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processMethods(clazz, addMeta);
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        processFields(clazz);
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtField f;
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (addMeta) {
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            f = new CtField(classPool.get("javassist.tools.reflect.Metaobject"),
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                            metaobjectField, clazz);
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            f.setModifiers(Modifier.PROTECTED);
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz.addField(f, CtField.Initializer.byNewWithParams(metaobject));
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz.addMethod(CtNewMethod.getter(metaobjectGetter, f));
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz.addMethod(CtNewMethod.setter(metaobjectSetter, f));
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        f = new CtField(classPool.get("javassist.tools.reflect.ClassMetaobject"),
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        classobjectField, clazz);
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        f.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clazz.addField(f, CtField.Initializer.byNew(metaclass,
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                        new String[] { clazz.getName() }));
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clazz.addMethod(CtNewMethod.getter(classobjectAccessor, f));
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return true;
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void processMethods(CtClass clazz, boolean dontSearch)
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, NotFoundException
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod[] ms = clazz.getMethods();
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < ms.length; ++i) {
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtMethod m = ms[i];
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mod = m.getModifiers();
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (Modifier.isPublic(mod) && !Modifier.isAbstract(mod))
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                processMethods0(mod, clazz, m, i, dontSearch);
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void processMethods0(int mod, CtClass clazz,
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        CtMethod m, int identifier, boolean dontSearch)
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, NotFoundException
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod body;
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String name = m.getName();
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (isExcluded(name))   // internally-used method inherited
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return;             // from a reflective class.
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod m2;
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (m.getDeclaringClass() == clazz) {
29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (Modifier.isNative(mod))
30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return;
30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            m2 = m;
30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (Modifier.isFinal(mod)) {
30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                mod &= ~Modifier.FINAL;
30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                m2.setModifiers(mod);
30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else {
30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (Modifier.isFinal(mod))
31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return;
31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            mod &= ~Modifier.NATIVE;
31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            m2 = CtNewMethod.delegator(findOriginal(m, dontSearch), clazz);
31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            m2.setModifiers(mod);
31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz.addMethod(m2);
31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        m2.setName(ClassMetaobject.methodPrefix + identifier
31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                      + "_" + name);
32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (Modifier.isStatic(mod))
32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            body = trapStaticMethod;
32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            body = trapMethod;
32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod wmethod
32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            = CtNewMethod.wrapped(m.getReturnType(), name,
32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  m.getParameterTypes(), m.getExceptionTypes(),
32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  body, ConstParameter.integer(identifier),
33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  clazz);
33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        wmethod.setModifiers(mod);
33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clazz.addMethod(wmethod);
33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private CtMethod findOriginal(CtMethod m, boolean dontSearch)
33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws NotFoundException
33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (dontSearch)
33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return m;
34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String name = m.getName();
34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod[] ms = m.getDeclaringClass().getDeclaredMethods();
34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < ms.length; ++i) {
34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String orgName = ms[i].getName();
34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (orgName.endsWith(name)
34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                && orgName.startsWith(ClassMetaobject.methodPrefix)
34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                && ms[i].getSignature().equals(m.getSignature()))
34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return ms[i];
34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return m;
35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void processFields(CtClass clazz)
35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException, NotFoundException
35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtField[] fs = clazz.getDeclaredFields();
35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < fs.length; ++i) {
35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtField f = fs[i];
36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mod = f.getModifiers();
36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                mod |= Modifier.STATIC;
36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                String name = f.getName();
36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                CtClass ftype = f.getType();
36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                CtMethod wmethod
36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    = CtNewMethod.wrapped(ftype, readPrefix + name,
36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                          readParam, null, trapRead,
36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                          ConstParameter.string(name),
36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                          clazz);
37069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                wmethod.setModifiers(mod);
37169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                clazz.addMethod(wmethod);
37269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                CtClass[] writeParam = new CtClass[2];
37369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                writeParam[0] = classPool.get("java.lang.Object");
37469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                writeParam[1] = ftype;
37569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                wmethod = CtNewMethod.wrapped(CtClass.voidType,
37669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                writePrefix + name,
37769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                writeParam, null, trapWrite,
37869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                ConstParameter.string(name), clazz);
37969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                wmethod.setModifiers(mod);
38069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                clazz.addMethod(wmethod);
38169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
38269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
38369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
38469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
385