class AbstractProxyBytecodeTransformer implements ProxyBytecodeTransformer
{
    private ClassPool classPool;

    /**
     *
     * @param classPool
     *            Classpool used to make a CtClass
     */
    public AbstractProxyBytecodeTransformer(ClassPool classPool) {
        this.classPool = classPool;
    }

    public byte[] transform(byte[] byteCode) throws Exception {
        CtClass cc = classPool.makeClass(new ByteArrayInputStream(byteCode), false);
        try {
            String initFieldName = INIT_FIELD_PREFIX + generateRandomString();
            addStaticInitStateField(cc, initFieldName);

            String initCode = getInitCall(cc, initFieldName);

            addInitCallToMethods(cc, initFieldName, initCode);
            return cc.toBytecode();
        } finally {
            cc.detach();
        }
    }

    /**
     * Builds the Java code String which should be executed to initialize the proxy
     *
     * @param cc
     *            CtClass from new definition
     * @param random
     *            randomly generated String
     * @return Java code to call init the proxy
     */
    protected abstract String getInitCall(CtClass cc, String random) throws Exception;

    protected String generateRandomString() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * Adds the initCall as Java code to all the non static methods of the class. The initialization is only done if
     * clinitFieldName is false. Responsibility to set the clinitFieldName is on the initCall.
     *
     * @param cc
     *            CtClass to be modified
     * @param clinitFieldName
     *            field name in CtClass
     * @param initCall
     *            Java code to initialize the Proxy
     * @throws Exception
     */
    protected void addInitCallToMethods(CtClass cc, String clinitFieldName, String initCall) throws Exception {<FILL_FUNCTION_BODY>}

    /**
     * Adds a static boolean field to the class indicating the state of initialization
     *
     * @param cc
     *            CtClass to be modified
     * @param clinitFieldName
     *            field name in CtClass
     * @throws Exception
     */
    protected void addStaticInitStateField(CtClass cc, String clinitFieldName) throws Exception {
        CtField f = new CtField(CtClass.booleanType, clinitFieldName, cc);
        f.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
        // init value "true" will be inside clinit, so the field wont actually be initialized on redefinition
        cc.addField(f, "true");
    }
}

        CtMethod[] methods = cc.getDeclaredMethods();
        for (CtMethod ctMethod : methods) {
            if (!ctMethod.isEmpty() && !Modifier.isStatic(ctMethod.getModifiers())) {
                ctMethod.insertBefore("if(!" + clinitFieldName + "){synchronized(" + cc.getName() + ".class){if(!"
                        + clinitFieldName + "){" + initCall + "}}}");
            }
        }
    
<no_super_class>