
/*
 * Copyright (C) 2014 Archie L. Cobbs. All rights reserved.
 *
 * $Id$
 */

package org.jsimpledb;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.regex.Pattern;

import org.jsimpledb.util.AnnotationScanner;

/**
 * Support superclass for field annotation scanners.
 */
abstract class AbstractFieldScanner<T, A extends Annotation> extends AnnotationScanner<T, A> {

    private final boolean autogenFields;

    AbstractFieldScanner(JClass<T> jclass, Class<A> annotationType, boolean autogenFields) {
        super(jclass, annotationType);
        this.autogenFields = autogenFields;
    }

    protected abstract A getDefaultAnnotation();

    @Override
    protected A getAnnotation(Method method) {

        // Look for existing annotation
        final A annotation = super.getAnnotation(method);
        if (annotation != null)
            return annotation;

        // Check for auto-generated bean property getter method
        if (this.isAutoPropertyCandidate(method))
            return this.getDefaultAnnotation();

        // Skip this method
        return null;
    }

    protected boolean isAutoPropertyCandidate(Method method) {
        if (!this.autogenFields)
            return false;
        if ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.STATIC)) != Modifier.ABSTRACT)
            return false;
        if (!Pattern.compile("(is|get)(.+)").matcher(method.getName()).matches())
            return false;
        if (method.getParameterTypes().length != 0)
            return false;
        if (method.getReturnType() == Void.TYPE)
            return false;
        return true;
    }
}


@@ -1273,32 +1273,113 @@
   return false;%0A
+        if (this.isOverriddenByConcreteMethod(method))%0A            return false;%0A
         if ((met
@@ -1773,12 +1773,743 @@
 e;%0A    %7D
+%0A%0A    private boolean isOverriddenByConcreteMethod(Method method) %7B%0A        final Class%3C?%3E methodType = method.getDeclaringClass();%0A        for (Class%3C?%3E type = this.jclass.typeToken.getRawType();%0A          type != null && methodType.isAssignableFrom(type) && !type.equals(methodType);%0A          type = type.getSuperclass()) %7B%0A            final Method otherMethod;%0A            try %7B%0A                otherMethod = type.getDeclaredMethod(method.getName(), method.getParameterTypes());%0A            %7D catch (NoSuchMethodException e) %7B%0A                continue;%0A            %7D%0A            if (otherMethod != null && (otherMethod.getModifiers() & Modifier.ABSTRACT) == 0)%0A                return true;%0A        %7D%0A        return false;%0A    %7D
 %0A%7D%0A%0A

Fix bug where an abstract method overridden by a concrete method in a subclass would be incorrectly considered for auto-generated properties.