class AnonymousClassInfo {
    // name of the anonymous class
    String className;

    // signatures
    String classSignature;
    String methodSignature;
    String fieldsSignature;
    String enclosingMethodSignature;


    public AnonymousClassInfo(Class c) {
        this.className = c.getName();

        StringBuilder classSignature = new StringBuilder(c.getSuperclass().getName());
        for (Class intef : c.getInterfaces()) {
            classSignature.append(";");
            classSignature.append(intef.getName());
        }
        this.classSignature = classSignature.toString();

        StringBuilder methodsSignature = new StringBuilder();
        for (Method m : c.getDeclaredMethods()) {
            getMethodSignature(methodsSignature, m);
        }
        this.methodSignature = methodsSignature.toString();

        StringBuilder fieldsSignature = new StringBuilder();
        for (Field f : c.getDeclaredFields()) {
            // replace declarig class for constant because of unit tests (class name change)
            fieldsSignature.append(f.getType().getName());
            fieldsSignature.append(" ");
            fieldsSignature.append(f.getName());
            fieldsSignature.append(";");
        }
        this.fieldsSignature = fieldsSignature.toString();

        StringBuilder enclosingMethodSignature = new StringBuilder();
        Method enclosingMethod = c.getEnclosingMethod();
        if (enclosingMethod != null) {
            getMethodSignature(enclosingMethodSignature, enclosingMethod);
        }
        this.enclosingMethodSignature = enclosingMethodSignature.toString();

    }

    public AnonymousClassInfo(String className) {
        this.className = className;
    }

    private void getMethodSignature(StringBuilder methodsSignature, Method m) {
        methodsSignature.append(m.getReturnType().getName());
        methodsSignature.append(" ");
        methodsSignature.append(m.getName());
        methodsSignature.append("(");
        for (Class paramType : m.getParameterTypes())
            methodsSignature.append(paramType.getName());
        methodsSignature.append(")");
        methodsSignature.append(";");
    }

    public AnonymousClassInfo(CtClass c) {
        try {
            this.className = c.getName();

            StringBuilder classSignature = new StringBuilder(c.getSuperclassName());
            for (CtClass intef : c.getInterfaces()) {
                classSignature.append(";");
                classSignature.append(intef.getName());
            }
            this.classSignature = classSignature.toString();

            StringBuilder methodsSignature = new StringBuilder();
            for (CtMethod m : c.getDeclaredMethods()) {
                getMethodSignature(methodsSignature, m);
            }
            this.methodSignature = methodsSignature.toString();

            StringBuilder fieldsSignature = new StringBuilder();
            for (CtField f : c.getDeclaredFields()) {
                fieldsSignature.append(f.getType().getName());
                fieldsSignature.append(" ");
                fieldsSignature.append(f.getName());
                fieldsSignature.append(";");
            }
            this.fieldsSignature = fieldsSignature.toString();

            StringBuilder enclosingMethodSignature = new StringBuilder();
            try {
                CtMethod enclosingMethod = c.getEnclosingMethod();
                if (enclosingMethod != null) {
                    getMethodSignature(enclosingMethodSignature, enclosingMethod);
                }
            } catch (Exception e) {
                // OK, enclosing method not defined or out of scope
            }
            this.enclosingMethodSignature = enclosingMethodSignature.toString();

        } catch (Throwable t) {
            throw new IllegalStateException("Error creating AnonymousClassInfo from " + c.getName(), t);
        }
    }

    private void getMethodSignature(StringBuilder methodsSignature, CtMethod m) throws NotFoundException {<FILL_FUNCTION_BODY>}

    public String getClassName() {
        return className;
    }

    public String getClassSignature() {
        return classSignature;
    }

    public String getMethodSignature() {
        return methodSignature;
    }

    public String getFieldsSignature() {
        return fieldsSignature;
    }

    public String getEnclosingMethodSignature() {
        return enclosingMethodSignature;
    }

    /**
     * Exact match including enclosing method.
     */
    public boolean matchExact(AnonymousClassInfo other) {
        return getClassSignature().equals(other.getClassSignature()) &&
                getMethodSignature().equals(other.getMethodSignature()) &&
                getFieldsSignature().equals(other.getFieldsSignature()) &&
                getEnclosingMethodSignature().equals(other.getEnclosingMethodSignature());
    }

    /**
     * Exact match of class, interfaces, declared methods and fields.
     * May be different enclosing method.
     */
    public boolean matchSignatures(AnonymousClassInfo other) {
        return getClassSignature().equals(other.getClassSignature()) &&
                getMethodSignature().equals(other.getMethodSignature()) &&
                getFieldsSignature().equals(other.getFieldsSignature());
    }

    /**
     * The least matching variant - same class signature can be still resolved by hotswap.
     */
    public boolean matchClassSignature(AnonymousClassInfo other) {
        return getClassSignature().equals(other.getClassSignature());
    }
}

        methodsSignature.append(m.getReturnType().getName());
        methodsSignature.append(" ");
        methodsSignature.append(m.getName());
        methodsSignature.append("(");
        for (CtClass paramType : m.getParameterTypes())
            methodsSignature.append(paramType.getName());
        methodsSignature.append(")");
        methodsSignature.append(";");
    
<no_super_class>