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

com.feilong.lib.javassist.compiler.AccessorMaker 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.compiler;

import java.util.HashMap;
import java.util.Map;

import com.feilong.lib.javassist.CannotCompileException;
import com.feilong.lib.javassist.ClassPool;
import com.feilong.lib.javassist.CtClass;
import com.feilong.lib.javassist.NotFoundException;
import com.feilong.lib.javassist.bytecode.AccessFlag;
import com.feilong.lib.javassist.bytecode.Bytecode;
import com.feilong.lib.javassist.bytecode.ClassFile;
import com.feilong.lib.javassist.bytecode.ConstPool;
import com.feilong.lib.javassist.bytecode.Descriptor;
import com.feilong.lib.javassist.bytecode.ExceptionsAttribute;
import com.feilong.lib.javassist.bytecode.FieldInfo;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.javassist.bytecode.SyntheticAttribute;

/**
 * AccessorMaker maintains accessors to private members of an enclosing
 * class. It is necessary for compiling a method in an inner class.
 */
public class AccessorMaker{

    private final CtClass             clazz;

    private int                       uniqueNumber;

    private final Map accessors;

    static final String               lastParamType = com.feilong.lib.javassist.runtime.Inner.class.getName();

    public AccessorMaker(CtClass c){
        clazz = c;
        uniqueNumber = 1;
        accessors = new HashMap<>();
    }

    public String getConstructor(CtClass c,String desc,MethodInfo orig) throws CompileError{
        String key = ":" + desc;
        String consDesc = (String) accessors.get(key);
        if (consDesc != null){
            return consDesc; // already exists.
        }

        consDesc = Descriptor.appendParameter(lastParamType, desc);
        ClassFile cf = clazz.getClassFile(); // turn on the modified flag. 
        try{
            ConstPool cp = cf.getConstPool();
            ClassPool pool = clazz.getClassPool();
            MethodInfo minfo = new MethodInfo(cp, MethodInfo.nameInit, consDesc);
            minfo.setAccessFlags(0);
            minfo.addAttribute(new SyntheticAttribute(cp));
            ExceptionsAttribute ea = orig.getExceptionsAttribute();
            if (ea != null){
                minfo.addAttribute(ea.copy(cp, null));
            }

            CtClass[] params = Descriptor.getParameterTypes(desc, pool);
            Bytecode code = new Bytecode(cp);
            code.addAload(0);
            int regno = 1;
            for (CtClass param : params){
                regno += code.addLoad(regno, param);
            }
            code.setMaxLocals(regno + 1); // the last parameter is added.
            code.addInvokespecial(clazz, MethodInfo.nameInit, desc);

            code.addReturn(null);
            minfo.setCodeAttribute(code.toCodeAttribute());
            cf.addMethod(minfo);
        }catch (CannotCompileException e){
            throw new CompileError(e);
        }catch (NotFoundException e){
            throw new CompileError(e);
        }

        accessors.put(key, consDesc);
        return consDesc;
    }

    /**
     * Returns the name of the method for accessing a private method.
     *
     * @param name
     *            the name of the private method.
     * @param desc
     *            the descriptor of the private method.
     * @param accDesc
     *            the descriptor of the accessor method. The first
     *            parameter type is clazz.
     *            If the private method is static,
     *            accDesc must be identical to desc.
     * 
     * @param orig
     *            the method info of the private method.
     * @return
     */
    public String getMethodAccessor(String name,String desc,String accDesc,MethodInfo orig) throws CompileError{
        String key = name + ":" + desc;
        String accName = (String) accessors.get(key);
        if (accName != null){
            return accName; // already exists.
        }

        ClassFile cf = clazz.getClassFile(); // turn on the modified flag. 
        accName = findAccessorName(cf);
        try{
            ConstPool cp = cf.getConstPool();
            ClassPool pool = clazz.getClassPool();
            MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
            minfo.setAccessFlags(AccessFlag.STATIC);
            minfo.addAttribute(new SyntheticAttribute(cp));
            ExceptionsAttribute ea = orig.getExceptionsAttribute();
            if (ea != null){
                minfo.addAttribute(ea.copy(cp, null));
            }

            CtClass[] params = Descriptor.getParameterTypes(accDesc, pool);
            int regno = 0;
            Bytecode code = new Bytecode(cp);
            for (CtClass param : params){
                regno += code.addLoad(regno, param);
            }

            code.setMaxLocals(regno);
            if (desc == accDesc){
                code.addInvokestatic(clazz, name, desc);
            }else{
                code.addInvokevirtual(clazz, name, desc);
            }

            code.addReturn(Descriptor.getReturnType(desc, pool));
            minfo.setCodeAttribute(code.toCodeAttribute());
            cf.addMethod(minfo);
        }catch (CannotCompileException e){
            throw new CompileError(e);
        }catch (NotFoundException e){
            throw new CompileError(e);
        }

        accessors.put(key, accName);
        return accName;
    }

    /**
     * Returns the method_info representing the added getter.
     */
    public MethodInfo getFieldGetter(FieldInfo finfo,boolean is_static) throws CompileError{
        String fieldName = finfo.getName();
        String key = fieldName + ":getter";
        Object res = accessors.get(key);
        if (res != null){
            return (MethodInfo) res; // already exists.
        }

        ClassFile cf = clazz.getClassFile(); // turn on the modified flag. 
        String accName = findAccessorName(cf);
        try{
            ConstPool cp = cf.getConstPool();
            ClassPool pool = clazz.getClassPool();
            String fieldType = finfo.getDescriptor();
            String accDesc;
            if (is_static){
                accDesc = "()" + fieldType;
            }else{
                accDesc = "(" + Descriptor.of(clazz) + ")" + fieldType;
            }

            MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
            minfo.setAccessFlags(AccessFlag.STATIC);
            minfo.addAttribute(new SyntheticAttribute(cp));
            Bytecode code = new Bytecode(cp);
            if (is_static){
                code.addGetstatic(Bytecode.THIS, fieldName, fieldType);
            }else{
                code.addAload(0);
                code.addGetfield(Bytecode.THIS, fieldName, fieldType);
                code.setMaxLocals(1);
            }

            code.addReturn(Descriptor.toCtClass(fieldType, pool));
            minfo.setCodeAttribute(code.toCodeAttribute());
            cf.addMethod(minfo);
            accessors.put(key, minfo);
            return minfo;
        }catch (CannotCompileException e){
            throw new CompileError(e);
        }catch (NotFoundException e){
            throw new CompileError(e);
        }
    }

    /**
     * Returns the method_info representing the added setter.
     */
    public MethodInfo getFieldSetter(FieldInfo finfo,boolean is_static) throws CompileError{
        String fieldName = finfo.getName();
        String key = fieldName + ":setter";
        Object res = accessors.get(key);
        if (res != null){
            return (MethodInfo) res; // already exists.
        }

        ClassFile cf = clazz.getClassFile(); // turn on the modified flag. 
        String accName = findAccessorName(cf);
        try{
            ConstPool cp = cf.getConstPool();
            ClassPool pool = clazz.getClassPool();
            String fieldType = finfo.getDescriptor();
            String accDesc;
            if (is_static){
                accDesc = "(" + fieldType + ")V";
            }else{
                accDesc = "(" + Descriptor.of(clazz) + fieldType + ")V";
            }

            MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
            minfo.setAccessFlags(AccessFlag.STATIC);
            minfo.addAttribute(new SyntheticAttribute(cp));
            Bytecode code = new Bytecode(cp);
            int reg;
            if (is_static){
                reg = code.addLoad(0, Descriptor.toCtClass(fieldType, pool));
                code.addPutstatic(Bytecode.THIS, fieldName, fieldType);
            }else{
                code.addAload(0);
                reg = code.addLoad(1, Descriptor.toCtClass(fieldType, pool)) + 1;
                code.addPutfield(Bytecode.THIS, fieldName, fieldType);
            }

            code.addReturn(null);
            code.setMaxLocals(reg);
            minfo.setCodeAttribute(code.toCodeAttribute());
            cf.addMethod(minfo);
            accessors.put(key, minfo);
            return minfo;
        }catch (CannotCompileException e){
            throw new CompileError(e);
        }catch (NotFoundException e){
            throw new CompileError(e);
        }
    }

    private String findAccessorName(ClassFile cf){
        String accName;
        do{
            accName = "access$" + uniqueNumber++;
        }while (cf.getMethod(accName) != null);
        return accName;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy