org.androidannotations.helper.ValidatorHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.androidannotations.helper.ValidatorHelper.java

Source

/**
 * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed To in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.androidannotations.helper;

import static java.util.Arrays.asList;
import static org.androidannotations.helper.AndroidConstants.LOG_DEBUG;
import static org.androidannotations.helper.AndroidConstants.LOG_ERROR;
import static org.androidannotations.helper.AndroidConstants.LOG_INFO;
import static org.androidannotations.helper.AndroidConstants.LOG_VERBOSE;
import static org.androidannotations.helper.AndroidConstants.LOG_WARN;
import static org.androidannotations.helper.CanonicalNameConstants.CLIENT_HTTP_REQUEST_FACTORY;
import static org.androidannotations.helper.CanonicalNameConstants.CLIENT_HTTP_REQUEST_INTERCEPTOR;
import static org.androidannotations.helper.CanonicalNameConstants.HTTP_MESSAGE_CONVERTER;
import static org.androidannotations.helper.CanonicalNameConstants.INTERNET_PERMISSION;
import static org.androidannotations.helper.CanonicalNameConstants.WAKELOCK_PERMISSION;
import static org.androidannotations.helper.ModelConstants.GENERATION_SUFFIX;
import static org.androidannotations.helper.ModelConstants.VALID_ANDROID_ANNOTATIONS;
import static org.androidannotations.helper.ModelConstants.VALID_ENHANCED_COMPONENT_ANNOTATIONS;
import static org.androidannotations.helper.ModelConstants.VALID_ENHANCED_VIEW_SUPPORT_ANNOTATIONS;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ErrorType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.EIntentService;
import org.androidannotations.annotations.EReceiver;
import org.androidannotations.annotations.EService;
import org.androidannotations.annotations.OnActivityResult;
import org.androidannotations.annotations.Receiver;
import org.androidannotations.annotations.Trace;
import org.androidannotations.annotations.ViewById;
import org.androidannotations.annotations.WakeLock;
import org.androidannotations.annotations.WakeLock.Level;
import org.androidannotations.annotations.rest.Delete;
import org.androidannotations.annotations.rest.Get;
import org.androidannotations.annotations.rest.Head;
import org.androidannotations.annotations.rest.Options;
import org.androidannotations.annotations.rest.Post;
import org.androidannotations.annotations.rest.Put;
import org.androidannotations.annotations.rest.Rest;
import org.androidannotations.annotations.sharedpreferences.DefaultBoolean;
import org.androidannotations.annotations.sharedpreferences.DefaultFloat;
import org.androidannotations.annotations.sharedpreferences.DefaultInt;
import org.androidannotations.annotations.sharedpreferences.DefaultLong;
import org.androidannotations.annotations.sharedpreferences.DefaultString;
import org.androidannotations.annotations.sharedpreferences.SharedPref;
import org.androidannotations.api.rest.RestClientErrorHandling;
import org.androidannotations.api.rest.RestClientHeaders;
import org.androidannotations.api.rest.RestClientRootUrl;
import org.androidannotations.api.rest.RestClientSupport;
import org.androidannotations.api.sharedpreferences.SharedPreferencesHelper;
import org.androidannotations.model.AndroidSystemServices;
import org.androidannotations.model.AnnotationElements;
import org.androidannotations.process.IsValid;

@SuppressWarnings("checkstyle:methodcount")
public class ValidatorHelper {

    private static final List<String> VALID_REST_INTERFACES = asList(RestClientHeaders.class.getName(),
            RestClientErrorHandling.class.getName(), RestClientRootUrl.class.getName(),
            RestClientSupport.class.getName());

    private static final List<String> ANDROID_FRAGMENT_QUALIFIED_NAMES = asList(CanonicalNameConstants.FRAGMENT,
            CanonicalNameConstants.SUPPORT_V4_FRAGMENT);

    private static final String METHOD_NAME_SET_ROOT_URL = "setRootUrl";
    private static final String METHOD_NAME_SET_AUTHENTICATION = "setAuthentication";
    private static final String METHOD_NAME_SET_BEARER_AUTH = "setBearerAuth";
    private static final String METHOD_NAME_GET_COOKIE = "getCookie";
    private static final String METHOD_NAME_GET_HEADER = "getHeader";

    private static final String METHOD_NAME_GET_ROOT_URL = "getRootUrl";

    private static final List<String> VALID_PREF_RETURN_TYPES = Arrays.asList("int", "boolean", "float", "long",
            CanonicalNameConstants.STRING, CanonicalNameConstants.STRING_SET);

    private static final List<String> INVALID_PREF_METHOD_NAMES = Arrays.asList("edit", "getSharedPreferences",
            "clear", "getEditor", "apply");

    private static final Collection<Integer> VALID_LOG_LEVELS = Arrays.asList(LOG_VERBOSE, LOG_DEBUG, LOG_INFO,
            LOG_WARN, LOG_ERROR);

    private static final List<Receiver.RegisterAt> VALID_ACTIVITY_REGISTER_AT = Arrays.asList(
            Receiver.RegisterAt.OnCreateOnDestroy, Receiver.RegisterAt.OnResumeOnPause,
            Receiver.RegisterAt.OnStartOnStop);
    private static final List<Receiver.RegisterAt> VALID_SERVICE_REGISTER_AT = Arrays
            .asList(Receiver.RegisterAt.OnCreateOnDestroy);
    private static final List<Receiver.RegisterAt> VALID_FRAGMENT_REGISTER_AT = Arrays.asList(
            Receiver.RegisterAt.OnCreateOnDestroy, Receiver.RegisterAt.OnResumeOnPause,
            Receiver.RegisterAt.OnStartOnStop, Receiver.RegisterAt.OnAttachOnDetach);

    private static final List<String> VALID_PREFERENCE_CLASSES = asList(CanonicalNameConstants.PREFERENCE_ACTIVITY,
            CanonicalNameConstants.PREFERENCE_FRAGMENT, CanonicalNameConstants.SUPPORT_V4_PREFERENCE_FRAGMENT,
            CanonicalNameConstants.MACHINARIUS_V4_PREFERENCE_FRAGMENT);

    protected final TargetAnnotationHelper annotationHelper;

    public final ValidatorParameterHelper param;

    private final ActionBarSherlockHelper thirdPartyLibHelper;

    public ValidatorHelper(TargetAnnotationHelper targetAnnotationHelper) {
        annotationHelper = targetAnnotationHelper;
        param = new ValidatorParameterHelper(annotationHelper);
        thirdPartyLibHelper = new ActionBarSherlockHelper(annotationHelper);
    }

    public void isNotFinal(Element element, IsValid valid) {
        if (annotationHelper.isFinal(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s cannot be used on a final element");
        }
    }

    public void isNotSynchronized(Element element, IsValid valid) {
        if (annotationHelper.isSynchronized(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s cannot be used on a synchronized element. If you think you shall need to use the synchronized keyword for a specific use case, please post on the mailing list.");
        }
    }

    public void isInterface(TypeElement element, IsValid valid) {
        if (!annotationHelper.isInterface(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s can only be used on an interface");
        }
    }

    public void isTopLevel(TypeElement element, IsValid valid) {
        if (!annotationHelper.isTopLevel(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s can only be used on a top level type");
        }
    }

    public void doesNotExtendInvalidInterfaces(TypeElement element, IsValid valid) {
        if (element.getInterfaces().size() > 0) {
            boolean isValid = true;

            for (TypeMirror iface : element.getInterfaces()) {
                if (!VALID_REST_INTERFACES.contains(iface.toString())) {
                    isValid = false;
                    break;
                }
            }

            if (!isValid) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "%s interfaces can only extend the following interfaces: " + VALID_REST_INTERFACES);
            }
        }
    }

    public void doesNotReturnPrimitive(ExecutableElement element, IsValid valid) {
        if (element.getReturnType().getKind().isPrimitive()) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s cannot return primitive");
        }
    }

    public void isNotPrivate(Element element, IsValid valid) {
        if (annotationHelper.isPrivate(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s cannot be used on a private element");
        }
    }

    public void isPublic(Element element, IsValid valid) {
        if (!annotationHelper.isPublic(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s cannot be used on a non public element");
        }
    }

    public void isStatic(Element element, IsValid valid) {
        if (!annotationHelper.isStatic(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s cannot be used on a non static inner element");
        }
    }

    public void enclosingElementIsNotAbstractIfNotAbstract(Element element, IsValid valid) {
        if (!annotationHelper.isAbstract(element) && annotationHelper.isAbstract(element.getEnclosingElement())) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s cannot be used on a non-abstract inner element whose outer element is abstract");
        }
    }

    public void enclosingElementHasEBeanAnnotation(Element element, AnnotationElements validatedElements,
            IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasClassAnnotation(element, enclosingElement, validatedElements, EBean.class, valid);
    }

    public void enclosingElementHasEActivity(Element element, AnnotationElements validatedElements, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasClassAnnotation(element, enclosingElement, validatedElements, EActivity.class, valid);
    }

    public void enclosingElementHasEActivityOrEFragment(Element element, AnnotationElements validatedElements,
            IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        @SuppressWarnings("unchecked")
        List<Class<? extends Annotation>> validAnnotations = asList(EActivity.class, EFragment.class);
        hasOneOfClassAnnotations(element, enclosingElement, validatedElements, validAnnotations, valid);
    }

    public void enclosingElementHasEActivityOrEFragmentOrEServiceOrEIntentService(Element element,
            AnnotationElements validatedElements, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        @SuppressWarnings("unchecked")
        List<Class<? extends Annotation>> validAnnotations = asList(EActivity.class, EFragment.class,
                EService.class, EIntentService.class);
        hasOneOfClassAnnotations(element, enclosingElement, validatedElements, validAnnotations, valid);
    }

    public void enclosingElementHasEFragment(Element element, AnnotationElements validatedElements, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasClassAnnotation(element, enclosingElement, validatedElements, EFragment.class, valid);
    }

    public void enclosingElementHasEIntentService(Element element, AnnotationElements validatedElements,
            IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasClassAnnotation(element, enclosingElement, validatedElements, EIntentService.class, valid);
    }

    public void enclosingElementHasEReceiver(Element element, AnnotationElements validatedElements, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasClassAnnotation(element, enclosingElement, validatedElements, EReceiver.class, valid);
    }

    public void hasEActivity(Element element, AnnotationElements validatedElements, IsValid valid) {
        hasClassAnnotation(element, element, validatedElements, EActivity.class, valid);
    }

    public void hasEActivityOrEFragment(Element element, AnnotationElements validatedElements, IsValid valid) {
        @SuppressWarnings("unchecked")
        List<Class<? extends Annotation>> validAnnotations = asList(EActivity.class, EFragment.class);
        hasOneOfClassAnnotations(element, element, validatedElements, validAnnotations, valid);
    }

    public void enclosingElementHasEnhancedViewSupportAnnotation(Element element,
            AnnotationElements validatedElements, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasOneOfClassAnnotations(element, enclosingElement, validatedElements,
                VALID_ENHANCED_VIEW_SUPPORT_ANNOTATIONS, valid);
    }

    public void enclosingElementHasEnhancedComponentAnnotation(Element element,
            AnnotationElements validatedElements, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasOneOfClassAnnotations(element, enclosingElement, validatedElements, VALID_ENHANCED_COMPONENT_ANNOTATIONS,
                valid);
    }

    public void enclosingElementHasAndroidAnnotation(Element element, AnnotationElements validatedElements,
            IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        hasOneOfClassAnnotations(element, enclosingElement, validatedElements, VALID_ANDROID_ANNOTATIONS, valid);
    }

    private void hasClassAnnotation(Element reportElement, Element element, AnnotationElements validatedElements,
            Class<? extends Annotation> validAnnotation, IsValid valid) {
        List<Class<? extends Annotation>> validAnnotations = new ArrayList<Class<? extends Annotation>>();
        validAnnotations.add(validAnnotation);
        hasOneOfClassAnnotations(reportElement, element, validatedElements, validAnnotations, valid);
    }

    private void hasOneOfClassAnnotations(Element reportElement, Element element,
            AnnotationElements validatedElements, List<Class<? extends Annotation>> validAnnotations,
            IsValid valid) {

        boolean foundAnnotation = false;
        for (Class<? extends Annotation> validAnnotation : validAnnotations) {
            if (element.getAnnotation(validAnnotation) != null) {
                foundAnnotation = true;
                break;
            }
        }

        if (!foundAnnotation) {
            valid.invalidate();
            annotationHelper.printAnnotationError(reportElement, "%s can only be used in a class annotated with "
                    + getFormattedValidEnhancedBeanAnnotationTypes(validAnnotations) + ".");
        }
    }

    private String getFormattedValidEnhancedBeanAnnotationTypes(List<Class<? extends Annotation>> annotations) {
        StringBuilder sb = new StringBuilder();
        if (!annotations.isEmpty()) {
            sb.append(TargetAnnotationHelper.annotationName(annotations.get(0)));

            for (int i = 1; i < annotations.size(); i++) {
                sb.append(", ");
                sb.append(TargetAnnotationHelper.annotationName(annotations.get(i)));
            }
        }

        return sb.toString();
    }

    public void hasViewByIdAnnotation(Element element, AnnotationElements validatedElements, IsValid valid) {
        String error = "can only be used with annotation";
        elementHasAnnotation(ViewById.class, element, validatedElements, valid, error);
    }

    public void enclosingElementHasRestAnnotation(Element element, AnnotationElements validatedElements,
            IsValid valid) {
        String error = "can only be used in an interface annotated with";
        enclosingElementHasAnnotation(Rest.class, element, validatedElements, valid, error);
    }

    public void enclosingMethodHasAnnotation(Class<? extends Annotation> annotation, Element element,
            AnnotationElements validatedElements, IsValid valid) {
        String error = "can only be used with a method annotated with";
        enclosingElementHasAnnotation(annotation, element, validatedElements, valid, error);
    }

    public void enclosingElementHasAnnotation(Class<? extends Annotation> annotation, Element element,
            AnnotationElements validatedElements, IsValid valid, String error) {
        Element enclosingElement = element.getEnclosingElement();
        elementHasAnnotation(annotation, enclosingElement, validatedElements, valid, error);
    }

    public void elementHasAnnotation(Class<? extends Annotation> annotation, Element element,
            AnnotationElements validatedElements, IsValid valid, String error) {

        Set<? extends Element> layoutAnnotatedElements = validatedElements
                .getRootAnnotatedElements(annotation.getName());

        if (!layoutAnnotatedElements.contains(element)) {
            valid.invalidate();
            if (element.getAnnotation(annotation) == null) {
                annotationHelper.printAnnotationError(element,
                        "%s " + error + " " + TargetAnnotationHelper.annotationName(annotation));
            }
        }
    }

    public boolean elementHasAnnotation(Class<? extends Annotation> annotation, Element element,
            AnnotationElements validatedElements) {
        Set<? extends Element> layoutAnnotatedElements = validatedElements
                .getRootAnnotatedElements(annotation.getName());
        return layoutAnnotatedElements.contains(element);
    }

    public void throwsOnlyRestClientException(ExecutableElement element, IsValid valid) {
        List<? extends TypeMirror> thrownTypes = element.getThrownTypes();
        if (thrownTypes.size() > 0) {
            if (thrownTypes.size() > 1 || !thrownTypes.get(0).toString()
                    .equals("org.springframework.web.client.RestClientException")) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "%s annotated methods can only declare throwing a RestClientException");
            }
        }
    }

    public void typeHasAnnotation(Class<? extends Annotation> annotation, Element element, IsValid valid) {
        TypeMirror elementType = element.asType();
        typeHasAnnotation(annotation, elementType, element, valid);
    }

    public void typeHasAnnotation(Class<? extends Annotation> annotation, TypeMirror elementType,
            Element reportingElement, IsValid valid) {
        Element typeElement = annotationHelper.getTypeUtils().asElement(elementType);
        if (!elementHasAnnotationSafe(annotation, typeElement)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(reportingElement,
                    "%s can only be used on an element annotated with "
                            + TargetAnnotationHelper.annotationName(annotation));
        }
    }

    public void typeOrTargetValueHasAnnotation(Class<? extends Annotation> annotation, Element element,
            IsValid valid) {
        DeclaredType targetAnnotationClassValue = annotationHelper.extractAnnotationClassParameter(element);

        if (targetAnnotationClassValue != null) {
            typeHasAnnotation(annotation, targetAnnotationClassValue, element, valid);

            if (!annotationHelper.getTypeUtils().isAssignable(targetAnnotationClassValue, element.asType())) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "The value of %s must be assignable into the annotated field");
            }
        } else {
            typeHasAnnotation(annotation, element, valid);
        }
    }

    private boolean elementHasAnnotationSafe(Class<? extends Annotation> annotation, Element element) {
        List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
        for (AnnotationMirror annotationMirror : annotationMirrors) {
            if (annotationMirror.getAnnotationType().toString().equals(annotation.getName())) {
                return true;
            }
        }
        return false;
    }

    public void hasHttpHeadersReturnType(ExecutableElement element, IsValid valid) {
        String returnType = element.getReturnType().toString();
        if (!returnType.equals("org.springframework.http.HttpHeaders")) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s annotated methods can only return a HttpHeaders, not " + returnType);
        }
    }

    public void hasSetOfHttpMethodReturnType(ExecutableElement element, IsValid valid) {
        TypeMirror returnType = element.getReturnType();
        String returnTypeString = returnType.toString();
        if (!returnTypeString.equals("java.util.Set<org.springframework.http.HttpMethod>")) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s annotated methods can only return a Set of HttpMethod, not " + returnTypeString);
        } else {
            DeclaredType declaredType = (DeclaredType) returnType;
            List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
            if (typeArguments.size() != 1) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "%s annotated methods can only return a parameterized Set (with HttpMethod)");
            } else {
                TypeMirror typeArgument = typeArguments.get(0);
                if (!typeArgument.toString().equals("org.springframework.http.HttpMethod")) {
                    valid.invalidate();
                    annotationHelper.printAnnotationError(element,
                            "%s annotated methods can only return a parameterized Set of HttpMethod, not "
                                    + typeArgument.toString());
                }
            }
        }
    }

    public void doesntThrowException(Element element, IsValid valid) {
        ExecutableElement executableElement = (ExecutableElement) element;

        if (executableElement.getThrownTypes().size() > 0) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s annotated methods should not declare throwing any exception");
        }
    }

    public void returnTypeIsVoidOrBoolean(ExecutableElement executableElement, IsValid valid) {
        TypeMirror returnType = executableElement.getReturnType();

        TypeKind returnKind = returnType.getKind();

        if (returnKind != TypeKind.BOOLEAN && returnKind != TypeKind.VOID
                && !returnType.toString().equals(CanonicalNameConstants.BOOLEAN)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(executableElement,
                    "%s can only be used on a method with a boolean or a void return type");
        }
    }

    public void returnTypeIsVoid(ExecutableElement executableElement, IsValid valid) {
        TypeMirror returnType = executableElement.getReturnType();

        if (returnType.getKind() != TypeKind.VOID) {
            valid.invalidate();
            annotationHelper.printAnnotationError(executableElement,
                    "%s can only be used on a method with a void return type");
        }
    }

    public void doesNotHaveTraceAnnotationAndReturnValue(ExecutableElement executableElement,
            AnnotationElements validatedElements, IsValid valid) {
        TypeMirror returnType = executableElement.getReturnType();

        if (elementHasAnnotation(Trace.class, executableElement, validatedElements)
                && returnType.getKind() != TypeKind.VOID) {
            annotationHelper.printAnnotationError(executableElement,
                    "@WakeLock annotated methods with a return value are not supported by @Trace");
        }
    }

    public void doesNotUseFlagsWithPartialWakeLock(Element element, AnnotationElements validatedElements,
            IsValid valid) {
        WakeLock annotation = element.getAnnotation(WakeLock.class);
        if (annotation.level().equals(Level.PARTIAL_WAKE_LOCK) && annotation.flags().length > 0) {
            annotationHelper.printAnnotationWarning(element,
                    "Flags have no effect when combined with a PARTIAL_WAKE_LOCK");
        }
    }

    public void returnTypeIsNotVoid(ExecutableElement executableElement, IsValid valid) {
        TypeMirror returnType = executableElement.getReturnType();

        if (returnType.getKind() == TypeKind.VOID) {
            valid.invalidate();
            annotationHelper.printAnnotationError(executableElement,
                    "%s can only be used on a method with a return type non void");
        }
    }

    public void extendsActivity(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.ACTIVITY, valid);
    }

    public void extendsFragment(Element element, IsValid valid) {
        extendsOneOfTypes(element, ANDROID_FRAGMENT_QUALIFIED_NAMES, valid);
    }

    public void extendsService(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.SERVICE, valid);
    }

    public void extendsIntentService(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.INTENT_SERVICE, valid);
    }

    public void extendsReceiver(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.BROADCAST_RECEIVER, valid);
    }

    public void extendsProvider(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.CONTENT_PROVIDER, valid);
    }

    public void extendsView(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.VIEW, valid);
    }

    public void extendsTextView(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.TEXT_VIEW, valid);
    }

    public void extendsViewGroup(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.VIEW_GROUP, valid);
    }

    public void extendsApplication(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.APPLICATION, valid);
    }

    public void extendsContext(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.CONTEXT, valid);
    }

    public void extendsMenuItem(Element element, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        String enclosingQualifiedName = enclosingElement.asType().toString();
        TypeElement enclosingTypeElement = annotationHelper.typeElementFromQualifiedName(enclosingQualifiedName);

        if (enclosingTypeElement != null) {
            if (thirdPartyLibHelper.usesActionBarSherlock(enclosingTypeElement)) {
                extendsType(element, CanonicalNameConstants.SHERLOCK_MENU_ITEM, valid);
            } else {
                extendsType(element, CanonicalNameConstants.MENU_ITEM, valid);
            }
        }
    }

    public void extendsOrmLiteDao(Element element, IsValid valid, OrmLiteHelper ormLiteHelper) {
        if (!valid.isValid()) {
            // we now that the element is invalid. early exit as the reason
            // could be missing ormlite classes
            return;
        }

        TypeMirror elementTypeMirror = element.asType();
        Types typeUtils = annotationHelper.getTypeUtils();

        DeclaredType daoParametrizedType = ormLiteHelper.getDaoParametrizedType();
        DeclaredType runtimeExceptionDaoParametrizedType = ormLiteHelper.getRuntimeExceptionDaoParametrizedType();

        // Checks that elementType extends Dao<?, ?> or
        // RuntimeExceptionDao<?, ?>
        if (!annotationHelper.isSubtype(elementTypeMirror, daoParametrizedType)
                && !annotationHelper.isSubtype(elementTypeMirror, runtimeExceptionDaoParametrizedType)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s can only be used on an element that extends " + daoParametrizedType.toString() //
                            + " or " + runtimeExceptionDaoParametrizedType.toString());
            return;
        }

        if (annotationHelper.isSubtype(elementTypeMirror, runtimeExceptionDaoParametrizedType) //
                && !typeUtils.isAssignable(ormLiteHelper.getTypedRuntimeExceptionDao(element), elementTypeMirror)) {

            boolean hasConstructor = false;
            Element elementType = typeUtils.asElement(elementTypeMirror);
            DeclaredType daoWithTypedParameters = ormLiteHelper.getTypedDao(element);
            for (ExecutableElement constructor : ElementFilter.constructorsIn(elementType.getEnclosedElements())) {
                List<? extends VariableElement> parameters = constructor.getParameters();
                if (parameters.size() == 1) {
                    TypeMirror type = parameters.get(0).asType();
                    if (annotationHelper.isSubtype(type, daoWithTypedParameters)) {
                        hasConstructor = true;
                    }
                }
            }
            if (!hasConstructor) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element, elementTypeMirror.toString()
                        + " requires a constructor that takes only a " + daoWithTypedParameters.toString());
            }
        }
    }

    public void extendsListOfView(Element element, IsValid valid) {
        DeclaredType elementType = (DeclaredType) element.asType();
        List<? extends TypeMirror> elementTypeArguments = elementType.getTypeArguments();

        TypeMirror viewType = annotationHelper.typeElementFromQualifiedName(CanonicalNameConstants.VIEW).asType();

        if (!elementType.toString().equals(CanonicalNameConstants.LIST) && elementTypeArguments.size() == 1
                && !annotationHelper.isSubtype(elementTypeArguments.get(0), viewType)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s can only be used on a " + CanonicalNameConstants.LIST
                    + " of elements extending " + CanonicalNameConstants.VIEW);
        }
    }

    public void extendsPreference(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.PREFERENCE, valid);
    }

    public void hasASqlLiteOpenHelperParameterizedType(Element element, IsValid valid) {
        TypeMirror helperType = annotationHelper.extractAnnotationParameter(element, "helper");

        TypeMirror openHelperType = annotationHelper
                .typeElementFromQualifiedName(CanonicalNameConstants.SQLLITE_OPEN_HELPER).asType();
        if (!annotationHelper.isSubtype(helperType, openHelperType)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s helper() parameter must extend " + CanonicalNameConstants.SQLLITE_OPEN_HELPER);
        }
    }

    public void applicationRegistered(Element element, AndroidManifest manifest, IsValid valid) {

        if (manifest.isLibraryProject()) {
            return;
        }

        String applicationClassName = manifest.getApplicationClassName();
        if (applicationClassName != null) {

            TypeElement typeElement = (TypeElement) element;

            String componentQualifiedName = typeElement.getQualifiedName().toString();
            String generatedComponentQualifiedName = componentQualifiedName + ModelConstants.GENERATION_SUFFIX;

            if (!typeElement.getModifiers().contains(Modifier.ABSTRACT)
                    && !applicationClassName.equals(generatedComponentQualifiedName)) {
                if (applicationClassName.equals(componentQualifiedName)) {
                    valid.invalidate();
                    annotationHelper.printAnnotationError(element,
                            "The AndroidManifest.xml file contains the original component, and not the AndroidAnnotations generated component. Please register "
                                    + generatedComponentQualifiedName + " instead of " + componentQualifiedName);
                } else {
                    annotationHelper.printAnnotationWarning(element,
                            "The component " + generatedComponentQualifiedName
                                    + " is not registered in the AndroidManifest.xml file.");
                }
            }
        } else {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "No application class registered in the AndroidManifest.xml");
        }

    }

    public void isSharedPreference(Element element, AnnotationElements validatedElements, IsValid valid) {

        TypeMirror type = element.asType();

        /*
         * The type is not available yet because it has just been generated
         */
        if (type instanceof ErrorType || type.getKind() == TypeKind.ERROR) {
            String elementTypeName = type.toString();

            boolean sharedPrefValidatedInRound = false;
            if (elementTypeName.endsWith(GENERATION_SUFFIX)) {
                String prefTypeName = elementTypeName.substring(0,
                        elementTypeName.length() - GENERATION_SUFFIX.length());
                prefTypeName = prefTypeName.replace("_.", ".");

                Set<? extends Element> sharedPrefElements = validatedElements
                        .getRootAnnotatedElements(SharedPref.class.getName());

                for (Element sharedPrefElement : sharedPrefElements) {
                    TypeElement sharedPrefTypeElement = (TypeElement) sharedPrefElement;

                    String sharedPrefQualifiedName = sharedPrefTypeElement.getQualifiedName().toString();

                    if (sharedPrefQualifiedName.endsWith(prefTypeName)) {
                        sharedPrefValidatedInRound = true;
                        break;
                    }
                }
            }

            if (!sharedPrefValidatedInRound) {
                valid.invalidate();
            }

        } else {
            extendsType(element, SharedPreferencesHelper.class.getName(), valid);
        }

    }

    public void extendsOneOfTypes(Element element, List<String> typeQualifiedNames, IsValid valid) {
        TypeMirror elementType = element.asType();

        for (String typeQualifiedName : typeQualifiedNames) {
            TypeElement typeElement = annotationHelper.typeElementFromQualifiedName(typeQualifiedName);
            if (typeElement != null) {
                TypeMirror expectedType = typeElement.asType();
                if (annotationHelper.isSubtype(elementType, expectedType)) {
                    return;
                }
            }
        }
        valid.invalidate();
        annotationHelper.printAnnotationError(element,
                "%s can only be used on an element that extends one of the following classes: "
                        + typeQualifiedNames);
    }

    public void extendsType(Element element, String typeQualifiedName, IsValid valid) {
        if (!extendsType(element, typeQualifiedName)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s can only be used on an element that extends " + typeQualifiedName);
        }
    }

    private boolean extendsType(Element element, String typeQualifiedName) {
        TypeMirror elementType = element.asType();

        TypeElement typeElement = annotationHelper.typeElementFromQualifiedName(typeQualifiedName);
        if (typeElement != null) {
            TypeMirror expectedType = typeElement.asType();
            return annotationHelper.isSubtype(elementType, expectedType);
        }
        return false;
    }

    public void allowedType(Element element, IsValid valid, TypeMirror fieldTypeMirror, List<String> allowedTypes) {

        String qualifiedName = fieldTypeMirror.toString();

        if (!allowedTypes.contains(qualifiedName)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "%s can only be used on a field which is a "
                    + allowedTypes.toString() + ", not " + qualifiedName);
        }
    }

    public void hasRoboGuiceJars(Element element, IsValid valid) {
        Elements elementUtils = annotationHelper.getElementUtils();

        if (elementUtils.getTypeElement(CanonicalNameConstants.ROBO_CONTEXT) == null) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "Could not find the RoboGuice framework in the classpath, the following class is missing: "
                            + CanonicalNameConstants.ROBO_CONTEXT);
        }

        if (elementUtils.getTypeElement(CanonicalNameConstants.ROBO_APPLICATION) != null) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "It seems you are using an old version of RoboGuice. Be sure to use version 3.0!");
        }

        if (elementUtils.getTypeElement(CanonicalNameConstants.ON_START_EVENT_OLD) != null) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "It seems you are using an old version of RoboGuice. Be sure to use version 3.0!");
        }
    }

    public void hasSpringAndroidJars(Element element, IsValid valid) {
        Elements elementUtils = annotationHelper.getElementUtils();

        if (elementUtils.getTypeElement(CanonicalNameConstants.REST_TEMPLATE) == null) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "Could not find the SpringAndroid framework in the classpath, the following class is missing: "
                            + CanonicalNameConstants.REST_TEMPLATE);
        }
    }

    public void hasOrmLiteJars(Element element, IsValid valid) {
        Elements elementUtils = annotationHelper.getElementUtils();

        if (elementUtils.getTypeElement(CanonicalNameConstants.DAO) == null) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "Could not find the OrmLite framework in the classpath, the following class is missing: "
                            + CanonicalNameConstants.DAO);
        }
    }

    public void androidService(AndroidSystemServices androidSystemServices, Element element, IsValid valid) {
        TypeMirror serviceType = element.asType();
        if (!androidSystemServices.contains(serviceType)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "Unknown service type: " + serviceType.toString());
        }
    }

    public void isDeclaredType(Element element, IsValid valid) {
        if (!(element.asType() instanceof DeclaredType)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s can only be used on a field which is a declared type");
        }
    }

    public void isPrefMethod(Element element, IsValid valid) {
        if (!element.getKind().equals(ElementKind.METHOD)) {
            annotationHelper.printError(element,
                    "Only methods are allowed in an " + annotationHelper.annotationName() + " annotated interface");
        } else {
            ExecutableElement executableElement = (ExecutableElement) element;
            String methodName = executableElement.getSimpleName().toString();
            if (executableElement.getParameters().size() > 0) {
                annotationHelper.printError(element, "Method " + methodName + " should have no parameters in an "
                        + annotationHelper.annotationName() + " annotated interface");
            } else {

                String returnType = executableElement.getReturnType().toString();

                if (!VALID_PREF_RETURN_TYPES.contains(returnType)) {
                    annotationHelper.printError(element,
                            "Method " + methodName + " should only return preference simple types in an "
                                    + annotationHelper.annotationName() + " annotated interface");
                } else {
                    if (INVALID_PREF_METHOD_NAMES.contains(methodName)) {
                        annotationHelper.printError(element,
                                "The method name " + methodName + " is forbidden in an "
                                        + annotationHelper.annotationName() + " annotated interface");
                    } else {
                        return;
                    }
                }
            }
        }
        valid.invalidate();
    }

    public void hasCorrectDefaultAnnotation(ExecutableElement method, IsValid valid) {
        checkDefaultAnnotation(method, DefaultBoolean.class, "boolean",
                new TypeKindAnnotationCondition(TypeKind.BOOLEAN), valid);
        checkDefaultAnnotation(method, DefaultFloat.class, "float", new TypeKindAnnotationCondition(TypeKind.FLOAT),
                valid);
        checkDefaultAnnotation(method, DefaultInt.class, "int", new TypeKindAnnotationCondition(TypeKind.INT),
                valid);
        checkDefaultAnnotation(method, DefaultLong.class, "long", new TypeKindAnnotationCondition(TypeKind.LONG),
                valid);
        checkDefaultAnnotation(method, DefaultString.class, "String", new DefaultAnnotationCondition() {
            @Override
            public boolean correctReturnType(TypeMirror returnType) {
                return returnType.toString().equals(CanonicalNameConstants.STRING);
            }
        }, valid);
    }

    private interface DefaultAnnotationCondition {
        boolean correctReturnType(TypeMirror returnType);
    }

    private class TypeKindAnnotationCondition implements DefaultAnnotationCondition {

        private final TypeKind typeKind;

        public TypeKindAnnotationCondition(TypeKind typeKind) {
            this.typeKind = typeKind;
        }

        @Override
        public boolean correctReturnType(TypeMirror returnType) {
            return returnType.getKind() == typeKind;
        }

    }

    private <T extends Annotation> void checkDefaultAnnotation(ExecutableElement method, Class<T> annotationClass,
            String expectedReturnType, DefaultAnnotationCondition condition, IsValid valid) {
        T defaultAnnotation = method.getAnnotation(annotationClass);
        if (defaultAnnotation != null) {
            if (!condition.correctReturnType(method.getReturnType())) {
                annotationHelper.printAnnotationError(method, annotationClass.getName(),
                        TargetAnnotationHelper.annotationName(annotationClass)
                                + " can only be used on a method that returns a " + expectedReturnType);
                valid.invalidate();
            }
        }
    }

    @SuppressWarnings("unchecked")
    private static final List<Class<? extends Annotation>> REST_ANNOTATION_CLASSES = Arrays.asList(Get.class,
            Head.class, Options.class, Post.class, Put.class, Delete.class);

    public void unannotatedMethodReturnsRestTemplate(TypeElement typeElement, IsValid valid) {
        List<? extends Element> enclosedElements = typeElement.getEnclosedElements();
        boolean foundGetRestTemplateMethod = false;
        boolean foundSetRestTemplateMethod = false;
        boolean foundSetAuthenticationMethod = false;
        boolean foundSetBearerAuthMethod = false;
        boolean foundSetRootUrlMethod = false;
        boolean foundGetCookieMethod = false;
        boolean foundGetHeaderMethod = false;
        boolean foundGetRootUrlMethod = false;

        for (Element enclosedElement : enclosedElements) {
            if (enclosedElement.getKind() != ElementKind.METHOD) {
                valid.invalidate();
                annotationHelper.printError(enclosedElement, "Only methods are allowed in a "
                        + TargetAnnotationHelper.annotationName(Rest.class) + " annotated interface");
            } else {

                boolean hasRestAnnotation = false;
                for (Class<? extends Annotation> annotationClass : REST_ANNOTATION_CLASSES) {
                    if (enclosedElement.getAnnotation(annotationClass) != null) {
                        hasRestAnnotation = true;
                        break;
                    }
                }

                if (!hasRestAnnotation) {

                    ExecutableElement executableElement = (ExecutableElement) enclosedElement;
                    TypeMirror returnType = executableElement.getReturnType();
                    String simpleName = executableElement.getSimpleName().toString();

                    if (returnType.toString().equals(CanonicalNameConstants.REST_TEMPLATE)) {
                        if (executableElement.getParameters().size() > 0) {
                            valid.invalidate();
                            annotationHelper.printError(enclosedElement,
                                    "The method returning a RestTemplate should not declare any parameter in a "
                                            + TargetAnnotationHelper.annotationName(Rest.class)
                                            + " annotated interface");
                        } else {
                            if (foundGetRestTemplateMethod) {
                                valid.invalidate();
                                annotationHelper.printError(enclosedElement,
                                        "Only one method should declare returning a RestTemplate in a "
                                                + TargetAnnotationHelper.annotationName(Rest.class)
                                                + " annotated interface");
                            } else {
                                foundGetRestTemplateMethod = true;
                            }
                        }
                    } else if (simpleName.equals(METHOD_NAME_GET_ROOT_URL)) {
                        if (!returnType.toString().equals(CanonicalNameConstants.STRING)) {
                            valid.invalidate();
                            annotationHelper.printError(enclosedElement,
                                    "The method getRootUrl must return String on a "
                                            + TargetAnnotationHelper.annotationName(Rest.class)
                                            + " annotated interface");
                        }

                        if (executableElement.getParameters().size() != 0) {
                            valid.invalidate();
                            annotationHelper.printError(enclosedElement,
                                    "The method getRootUrl cannot have parameters on a "
                                            + TargetAnnotationHelper.annotationName(Rest.class)
                                            + " annotated interface");
                        }

                        if (!foundGetRootUrlMethod) {
                            foundGetRootUrlMethod = true;
                        } else {
                            valid.invalidate();
                            annotationHelper.printError(enclosedElement,
                                    "The can be only one getRootUrl method on a "
                                            + TargetAnnotationHelper.annotationName(Rest.class)
                                            + " annotated interface");
                        }
                    } else if (returnType.getKind() == TypeKind.VOID) {
                        List<? extends VariableElement> parameters = executableElement.getParameters();
                        if (parameters.size() == 1) {
                            VariableElement firstParameter = parameters.get(0);
                            if (firstParameter.asType().toString().equals(CanonicalNameConstants.REST_TEMPLATE)) {
                                if (!foundSetRestTemplateMethod) {
                                    foundSetRestTemplateMethod = true;
                                } else {
                                    valid.invalidate();
                                    annotationHelper.printError(enclosedElement,
                                            "You can only have oneRestTemplate setter method on a "
                                                    + TargetAnnotationHelper.annotationName(Rest.class)
                                                    + " annotated interface");

                                }
                            } else if (executableElement.getSimpleName().toString().equals(METHOD_NAME_SET_ROOT_URL)
                                    && !foundSetRootUrlMethod) {
                                foundSetRootUrlMethod = true;
                            } else if (executableElement.getSimpleName().toString()
                                    .equals(METHOD_NAME_SET_AUTHENTICATION) && !foundSetAuthenticationMethod) {
                                foundSetAuthenticationMethod = true;
                            } else if (executableElement.getSimpleName().toString()
                                    .equals(METHOD_NAME_SET_BEARER_AUTH) && !foundSetBearerAuthMethod) {
                                foundSetBearerAuthMethod = true;
                            } else {
                                valid.invalidate();
                                annotationHelper.printError(enclosedElement,
                                        "The method to set a RestTemplate should have only one RestTemplate parameter on a "
                                                + TargetAnnotationHelper.annotationName(Rest.class)
                                                + " annotated interface");

                            }
                        } else if (parameters.size() == 2) {
                            VariableElement firstParameter = parameters.get(0);
                            VariableElement secondParameter = parameters.get(1);
                            if (!(firstParameter.asType().toString().equals(CanonicalNameConstants.STRING)
                                    && secondParameter.asType().toString().equals(CanonicalNameConstants.STRING))) {
                                valid.invalidate();
                                annotationHelper.printError(enclosedElement,
                                        "The method to set headers, cookies, or HTTP Basic Auth should have only String parameters on a "
                                                + TargetAnnotationHelper.annotationName(Rest.class)
                                                + " annotated interface");
                            }
                        } else {
                            valid.invalidate();
                            annotationHelper.printError(enclosedElement,
                                    "The method to set a RestTemplate should have only one RestTemplate parameter on a "
                                            + TargetAnnotationHelper.annotationName(Rest.class)
                                            + " annotated interface");
                        }
                    } else if (returnType.toString().equals(CanonicalNameConstants.STRING)) {
                        List<? extends VariableElement> parameters = executableElement.getParameters();
                        if (parameters.size() == 1) {
                            VariableElement firstParameter = parameters.get(0);
                            if (firstParameter.asType().toString().equals(CanonicalNameConstants.STRING)) {
                                if (executableElement.getSimpleName().toString().equals(METHOD_NAME_GET_COOKIE)
                                        && !foundGetCookieMethod) {
                                    foundGetCookieMethod = true;
                                } else if (executableElement.getSimpleName().toString()
                                        .equals(METHOD_NAME_GET_HEADER) && !foundGetHeaderMethod) {
                                    foundGetHeaderMethod = true;
                                } else {
                                    valid.invalidate();
                                    annotationHelper.printError(enclosedElement,
                                            "Only one getCookie(String) and one getHeader(String) method are allowed on a "
                                                    + TargetAnnotationHelper.annotationName(Rest.class)
                                                    + " annotated interface");
                                }
                            } else {
                                valid.invalidate();
                                annotationHelper.printError(enclosedElement,
                                        "Only getCookie(String) and getHeader(String) can return a String on a "
                                                + TargetAnnotationHelper.annotationName(Rest.class)
                                                + " annotated interface");
                            }

                        } else {
                            valid.invalidate();
                            annotationHelper.printError(enclosedElement,
                                    "The only methods that can return a String on a "
                                            + TargetAnnotationHelper.annotationName(Rest.class)
                                            + " annotated interface are getCookie(String) and getHeader(String)");
                        }
                    } else {
                        valid.invalidate();
                        annotationHelper.printError(enclosedElement, "All methods should be annotated in a "
                                + TargetAnnotationHelper.annotationName(Rest.class)
                                + " annotated interface, except the ones that returns or set a RestTemplate");
                    }
                }
            }
        }
    }

    public void notAlreadyValidated(Element element, AnnotationElements validatedElements, IsValid valid) {
        if (validatedElements.getAllElements().contains(element)) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "%s annotated element cannot be used with the other annotations used on this element.");
        }
    }

    public void isAbstractOrHasEmptyOrContextConstructor(Element element, IsValid valid) {
        List<ExecutableElement> constructors = ElementFilter.constructorsIn(element.getEnclosedElements());

        if (!annotationHelper.isAbstract(element)) {
            if (constructors.size() == 1) {
                ExecutableElement constructor = constructors.get(0);

                if (!annotationHelper.isPrivate(constructor)) {
                    if (constructor.getParameters().size() > 1) {
                        annotationHelper.printAnnotationError(element,
                                "%s annotated element should have a constructor with one parameter max, of type "
                                        + CanonicalNameConstants.CONTEXT);
                        valid.invalidate();
                    } else if (constructor.getParameters().size() == 1) {
                        VariableElement parameter = constructor.getParameters().get(0);
                        if (!parameter.asType().toString().equals(CanonicalNameConstants.CONTEXT)) {
                            annotationHelper.printAnnotationError(element,
                                    "%s annotated element should have a constructor with one parameter max, of type "
                                            + CanonicalNameConstants.CONTEXT);
                            valid.invalidate();
                        }
                    }
                } else {
                    annotationHelper.printAnnotationError(element,
                            "%s annotated element should not have a private constructor");
                    valid.invalidate();
                }
            } else {
                annotationHelper.printAnnotationError(element,
                        "%s annotated element should have only one constructor");
                valid.invalidate();
            }
        }
    }

    public void isAbstractOrHasEmptyConstructor(Element element, IsValid valid) {
        List<ExecutableElement> constructors = ElementFilter.constructorsIn(element.getEnclosedElements());

        if (!annotationHelper.isAbstract(element)) {
            if (constructors.size() == 1) {
                ExecutableElement constructor = constructors.get(0);

                if (!annotationHelper.isPrivate(constructor)) {
                    if (constructor.getParameters().size() != 0) {
                        annotationHelper.printAnnotationError(element,
                                "%s annotated element should have an empty constructor");
                        valid.invalidate();
                    }
                } else {
                    annotationHelper.printAnnotationError(element,
                            "%s annotated element should not have a private constructor");
                    valid.invalidate();
                }
            } else {
                annotationHelper.printAnnotationError(element,
                        "%s annotated element should have only one constructor");
                valid.invalidate();
            }
        }
    }

    public void hasValidLogLevel(Element element, IsValid isValid) {

        Trace annotation = element.getAnnotation(Trace.class);
        Integer level = annotation.level();

        if (!VALID_LOG_LEVELS.contains(level)) {
            annotationHelper.printError(element, "Unrecognized log level.");
            isValid.invalidate();
        }

    }

    public void canBePutInABundle(Element element, IsValid isValid) {
        String typeString = element.asType().toString();

        if (!isKnownBundleCompatibleType(typeString)) {

            if (element.asType() instanceof DeclaredType) {

                DeclaredType declaredType = (DeclaredType) element.asType();
                typeString = declaredType.asElement().toString();

            } else if (element.asType() instanceof ArrayType) {
                ArrayType arrayType = (ArrayType) element.asType();
                TypeMirror componentType = arrayType.getComponentType();

                if (componentType instanceof DeclaredType) {

                    DeclaredType declaredType = (DeclaredType) componentType;
                    typeString = declaredType.asElement().toString();

                } else {
                    typeString = componentType.toString();
                }

            } else {
                typeString = element.asType().toString();
            }

            TypeElement elementType = annotationHelper.typeElementFromQualifiedName(typeString);

            if (elementType == null) {
                elementType = getArrayEnclosingType(typeString);

                if (elementType == null) {
                    annotationHelper.printAnnotationError(element,
                            "Unrecognized type. Please let your attribute be primitive or implement Serializable or Parcelable");
                    isValid.invalidate();
                }
            }

            if (elementType != null) {
                TypeElement parcelableType = annotationHelper
                        .typeElementFromQualifiedName(CanonicalNameConstants.PARCELABLE);
                TypeElement serializableType = annotationHelper
                        .typeElementFromQualifiedName("java.io.Serializable");
                if (!annotationHelper.isSubtype(elementType, parcelableType)
                        && !annotationHelper.isSubtype(elementType, serializableType)) {
                    annotationHelper.printAnnotationError(element,
                            "Unrecognized type. Please let your attribute be primitive or implement Serializable or Parcelable");
                    isValid.invalidate();
                }
            }
        }
    }

    private TypeElement getArrayEnclosingType(String typeString) {
        typeString = typeString.replace("[]", "");
        return annotationHelper.typeElementFromQualifiedName(typeString);
    }

    private boolean isKnownBundleCompatibleType(String type) {
        return BundleHelper.METHOD_SUFFIX_BY_TYPE_NAME.containsKey(type);
    }

    public void componentRegistered(Element element, AndroidManifest androidManifest, IsValid valid) {
        componentRegistered(element, androidManifest, true, valid);
    }

    public void componentRegistered(Element element, AndroidManifest androidManifest, boolean printWarning,
            IsValid valid) {
        TypeElement typeElement = (TypeElement) element;

        if (typeElement.getModifiers().contains(Modifier.ABSTRACT)) {
            return;
        }

        if (androidManifest.isLibraryProject()) {
            return;
        }

        String componentQualifiedName = typeElement.getQualifiedName().toString();
        String generatedComponentQualifiedName = componentQualifiedName + ModelConstants.GENERATION_SUFFIX;

        List<String> componentQualifiedNames = androidManifest.getComponentQualifiedNames();
        if (!componentQualifiedNames.contains(generatedComponentQualifiedName)) {
            String simpleName = typeElement.getSimpleName().toString();
            String generatedSimpleName = simpleName + ModelConstants.GENERATION_SUFFIX;
            if (componentQualifiedNames.contains(componentQualifiedName)) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "The AndroidManifest.xml file contains the original component, and not the AndroidAnnotations generated component. Please register "
                                + generatedSimpleName + " instead of " + simpleName);
            } else {
                if (printWarning) {
                    annotationHelper.printAnnotationWarning(element, "The component " + generatedSimpleName
                            + " is not registered in the AndroidManifest.xml file.");
                }
            }
        }

    }

    public void validateConverters(Element element, IsValid valid) {
        TypeMirror httpMessageConverterType = annotationHelper.typeElementFromQualifiedName(HTTP_MESSAGE_CONVERTER)
                .asType();
        TypeMirror httpMessageConverterTypeErased = annotationHelper.getTypeUtils()
                .erasure(httpMessageConverterType);
        List<DeclaredType> converters = annotationHelper.extractAnnotationClassArrayParameter(element,
                annotationHelper.getTarget(), "converters");

        if (converters == null || converters.isEmpty()) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element, "At least one converter is required");
            return;
        }

        for (DeclaredType converterType : converters) {
            TypeMirror erasedConverterType = annotationHelper.getTypeUtils().erasure(converterType);
            if (annotationHelper.isSubtype(erasedConverterType, httpMessageConverterTypeErased)) {
                Element converterElement = converterType.asElement();
                if (converterElement.getKind().isClass()) {
                    if (!annotationHelper.isAbstract(converterElement)) {
                        if (converterElement.getAnnotation(EBean.class) == null) {
                            List<ExecutableElement> constructors = ElementFilter
                                    .constructorsIn(converterElement.getEnclosedElements());
                            boolean hasPublicWithNoArgumentConstructor = false;
                            for (ExecutableElement constructor : constructors) {
                                if (annotationHelper.isPublic(constructor)
                                        && constructor.getParameters().isEmpty()) {
                                    hasPublicWithNoArgumentConstructor = true;
                                }
                            }
                            if (!hasPublicWithNoArgumentConstructor) {
                                valid.invalidate();
                                annotationHelper.printAnnotationError(element,
                                        "The converter class must have a public no argument constructor");
                            }
                        }
                    } else {
                        valid.invalidate();
                        annotationHelper.printAnnotationError(element, "The converter class must not be abstract");
                    }
                } else {
                    valid.invalidate();
                    annotationHelper.printAnnotationError(element, "The converter class must be a class");
                }
            } else {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "The converter class must be a subtype of " + HTTP_MESSAGE_CONVERTER);
            }
        }
    }

    public void validateInterceptors(Element element, IsValid valid) {
        TypeMirror clientHttpRequestInterceptorType = annotationHelper
                .typeElementFromQualifiedName(CLIENT_HTTP_REQUEST_INTERCEPTOR).asType();
        TypeMirror clientHttpRequestInterceptorTypeErased = annotationHelper.getTypeUtils()
                .erasure(clientHttpRequestInterceptorType);
        List<DeclaredType> interceptors = annotationHelper.extractAnnotationClassArrayParameter(element,
                annotationHelper.getTarget(), "interceptors");
        if (interceptors == null) {
            return;
        }
        for (DeclaredType interceptorType : interceptors) {
            TypeMirror erasedInterceptorType = annotationHelper.getTypeUtils().erasure(interceptorType);
            if (annotationHelper.isSubtype(erasedInterceptorType, clientHttpRequestInterceptorTypeErased)) {
                Element interceptorElement = interceptorType.asElement();
                if (interceptorElement.getKind().isClass()) {
                    if (!annotationHelper.isAbstract(interceptorElement)) {
                        if (interceptorElement.getAnnotation(EBean.class) == null) {
                            List<ExecutableElement> constructors = ElementFilter
                                    .constructorsIn(interceptorElement.getEnclosedElements());
                            boolean hasPublicWithNoArgumentConstructor = false;
                            for (ExecutableElement constructor : constructors) {
                                if (annotationHelper.isPublic(constructor)
                                        && constructor.getParameters().isEmpty()) {
                                    hasPublicWithNoArgumentConstructor = true;
                                }
                            }
                            if (!hasPublicWithNoArgumentConstructor) {
                                valid.invalidate();
                                annotationHelper.printAnnotationError(element,
                                        "The interceptor class must have a public no argument constructor or be annotated with @EBean");
                            }
                        }
                    } else {
                        valid.invalidate();
                        annotationHelper.printAnnotationError(element,
                                "The interceptor class must not be abstract");
                    }
                } else {
                    valid.invalidate();
                    annotationHelper.printAnnotationError(element, "The interceptor class must be a class");
                }
            } else {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "The interceptor class must be a subtype of " + CLIENT_HTTP_REQUEST_INTERCEPTOR);
            }
        }
    }

    public void isDebuggable(Element element, AndroidManifest androidManifest, IsValid valid) {
        if (!androidManifest.isDebuggable()) {
            valid.invalidate();
            annotationHelper.printAnnotationError(element,
                    "The application must be in debuggable mode. Please set android:debuggable to true in your AndroidManifest.xml file.");
        }
    }

    public void hasInternetPermission(Element element, AndroidManifest androidManifest, IsValid valid) {
        hasPermission(element, androidManifest, valid, INTERNET_PERMISSION);
    }

    public void hasWakeLockPermission(Element element, AndroidManifest androidManifest, IsValid valid) {
        hasPermission(element, androidManifest, valid, WAKELOCK_PERMISSION);
    }

    public void hasPermission(Element element, AndroidManifest androidManifest, IsValid valid,
            String permissionQualifiedName) {
        List<String> permissionQualifiedNames = androidManifest.getPermissionQualifiedNames();
        if (!permissionQualifiedNames.contains(permissionQualifiedName)) {
            if (androidManifest.isLibraryProject()) {
                annotationHelper.printAnnotationWarning(element,
                        "Your library should require the " + permissionQualifiedName + " permission.");
            } else {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "Your application must require the " + permissionQualifiedName + " permission.");
            }
        }
    }

    public void validateRequestFactory(Element element, IsValid valid) {
        TypeMirror clientHttpRequestFactoryType = annotationHelper
                .typeElementFromQualifiedName(CLIENT_HTTP_REQUEST_FACTORY).asType();
        DeclaredType requestFactory = annotationHelper.extractAnnotationClassParameter(element,
                annotationHelper.getTarget(), "requestFactory");
        if (requestFactory != null) {
            if (annotationHelper.isSubtype(requestFactory, clientHttpRequestFactoryType)) {
                Element requestFactoryElement = requestFactory.asElement();
                if (requestFactoryElement.getKind().isClass()) {
                    if (!annotationHelper.isAbstract(requestFactoryElement)) {
                        if (requestFactoryElement.getAnnotation(EBean.class) != null) {
                            return;
                        }
                        List<ExecutableElement> constructors = ElementFilter
                                .constructorsIn(requestFactoryElement.getEnclosedElements());
                        for (ExecutableElement constructor : constructors) {
                            if (annotationHelper.isPublic(constructor) && constructor.getParameters().isEmpty()) {
                                return;
                            }
                        }
                        valid.invalidate();
                        annotationHelper.printAnnotationError(element,
                                "The requestFactory class must have a public no argument constructor or must be annotated with @EBean");
                    } else {
                        valid.invalidate();
                        annotationHelper.printAnnotationError(element,
                                "The requestFactory class must not be abstract");
                    }
                } else {
                    valid.invalidate();
                    annotationHelper.printAnnotationError(element, "The requestFactory class must be a class");
                }
            } else {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "The requestFactory class must be a subtype of " + CLIENT_HTTP_REQUEST_FACTORY);
            }
        }
    }

    public void hasBeforeTextChangedMethodParameters(ExecutableElement executableElement, IsValid valid) {
        List<? extends VariableElement> parameters = executableElement.getParameters();
        boolean charSequenceParameterFound = false;
        boolean textViewParameterFound = false;
        for (VariableElement parameter : parameters) {
            String parameterType = parameter.asType().toString();
            if (parameterType.equals(CanonicalNameConstants.CHAR_SEQUENCE)) {
                if (charSequenceParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type java.lang.CharSequence");
                    valid.invalidate();
                }
                charSequenceParameterFound = true;
                continue;
            }
            if (parameterType.equals(CanonicalNameConstants.TEXT_VIEW)) {
                if (textViewParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type android.widget.TextView");
                    valid.invalidate();
                }
                textViewParameterFound = true;
                continue;
            }
            if (parameter.asType().getKind() == TypeKind.INT
                    || CanonicalNameConstants.INTEGER.equals(parameterType)) {
                String parameterName = parameter.toString();
                if ("start".equals(parameterName) || "count".equals(parameterName)
                        || "after".equals(parameterName)) {
                    continue;
                }
                annotationHelper.printAnnotationError(executableElement,
                        "Unrecognized parameter name. You can only have start, before, or count parameter name. Try to pick a parameter from android.text.TextWatcher.beforeTextChanged() method.");
                valid.invalidate();
                continue;
            }
            annotationHelper.printAnnotationError(executableElement, "Unrecognized parameter ("
                    + parameter.toString()
                    + "). %s can only have a android.widget.TextView parameter and/or parameters from android.text.TextWatcher.beforeTextChanged() method.");
            valid.invalidate();
        }
    }

    public void hasTextChangedMethodParameters(ExecutableElement executableElement, IsValid valid) {
        List<? extends VariableElement> parameters = executableElement.getParameters();
        boolean charSequenceParameterFound = false;
        boolean textViewParameterFound = false;
        for (VariableElement parameter : parameters) {
            String parameterType = parameter.asType().toString();
            if (parameterType.equals(CanonicalNameConstants.CHAR_SEQUENCE)) {
                if (charSequenceParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type java.lang.CharSequence");
                    valid.invalidate();
                }
                charSequenceParameterFound = true;
                continue;
            }
            if (parameterType.equals(CanonicalNameConstants.TEXT_VIEW)) {
                if (textViewParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type android.widget.TextView");
                    valid.invalidate();
                }
                textViewParameterFound = true;
                continue;
            }
            if (parameter.asType().getKind() == TypeKind.INT
                    || CanonicalNameConstants.INTEGER.equals(parameterType)) {
                String parameterName = parameter.toString();
                if ("start".equals(parameterName) || "before".equals(parameterName)
                        || "count".equals(parameterName)) {
                    continue;
                }
                annotationHelper.printAnnotationError(executableElement,
                        "Unrecognized parameter name. You can only have start, before, or count parameter name. Try to pick a prameter from the android.text.TextWatcher.onTextChanged() method.");
                valid.invalidate();
                continue;
            }
            annotationHelper.printAnnotationError(executableElement, "Unrecognized parameter ("
                    + parameter.toString()
                    + "). %s can only have a android.widget.TextView parameter and/or parameters from android.text.TextWatcher.onTextChanged() method.");
            valid.invalidate();
        }
    }

    public void hasAfterTextChangedMethodParameters(ExecutableElement executableElement, IsValid valid) {
        List<? extends VariableElement> parameters = executableElement.getParameters();
        boolean editableParameterFound = false;
        boolean textViewParameterFound = false;
        for (VariableElement parameter : parameters) {
            String parameterType = parameter.asType().toString();
            if (parameterType.equals(CanonicalNameConstants.EDITABLE)) {
                if (editableParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type android.text.Editable");
                    valid.invalidate();
                }
                editableParameterFound = true;
                continue;
            }
            if (parameterType.equals(CanonicalNameConstants.TEXT_VIEW)) {
                if (textViewParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type android.widget.TextView");
                    valid.invalidate();
                }
                textViewParameterFound = true;
                continue;
            }
            valid.invalidate();
            annotationHelper.printAnnotationError(executableElement,
                    "Unrecognized parameter type. %s can only have a android.widget.TextView parameter and/or an android.text.Editable parameter. See android.text.TextWatcher.afterTextChanged() for more informations.");
        }
    }

    public void hasSeekBarProgressChangeMethodParameters(ExecutableElement executableElement, IsValid valid) {
        List<? extends VariableElement> parameters = executableElement.getParameters();
        boolean seekBarParameterFound = false;
        boolean fromUserParameterFound = false;
        boolean progressParameterFound = false;
        for (VariableElement parameter : parameters) {
            String parameterType = parameter.asType().toString();
            if (parameterType.equals(CanonicalNameConstants.SEEKBAR)) {
                if (seekBarParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. You can declare only one parameter of type "
                                    + CanonicalNameConstants.SEEKBAR);
                    valid.invalidate();
                }
                seekBarParameterFound = true;
                continue;
            }
            if (parameter.asType().getKind() == TypeKind.INT
                    || CanonicalNameConstants.INTEGER.equals(parameterType)) {
                if (progressParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "You can have only one parameter of type " + CanonicalNameConstants.INTEGER);
                    valid.invalidate();
                }
                progressParameterFound = true;
                continue;
            }
            if (parameter.asType().getKind() == TypeKind.BOOLEAN
                    || CanonicalNameConstants.BOOLEAN.equals(parameterType)) {
                if (fromUserParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "You can have only one parameter of type " + CanonicalNameConstants.BOOLEAN);
                    valid.invalidate();
                }
                fromUserParameterFound = true;
                continue;
            }
            annotationHelper.printAnnotationError(executableElement, "Unrecognized parameter '"
                    + parameter.toString() + "'. %s signature should be " + executableElement.getSimpleName() + "("
                    + CanonicalNameConstants.SEEKBAR
                    + " seekBar, int progress, boolean fromUser). The 'fromUser' and 'progress' parameters are optional.");
            valid.invalidate();
        }
    }

    public void hasSeekBarTouchTrackingMethodParameters(ExecutableElement executableElement, IsValid valid) {
        List<? extends VariableElement> parameters = executableElement.getParameters();

        if (parameters.size() > 1) {
            annotationHelper.printAnnotationError(executableElement,
                    "Unrecognized parameter declaration. You can only have one parameter of type "
                            + CanonicalNameConstants.SEEKBAR + ". Try declaring "
                            + executableElement.getSimpleName() + "(" + CanonicalNameConstants.SEEKBAR
                            + " seekBar);");
            valid.invalidate();
            return;
        }

        if (parameters.size() == 1) {
            String parameterType = parameters.get(0).asType().toString();
            if (!parameterType.equals(CanonicalNameConstants.SEEKBAR)) {
                annotationHelper.printAnnotationError(executableElement,
                        "Unrecognized parameter declaration. You can only have one parameter of type "
                                + CanonicalNameConstants.SEEKBAR + ". Try declaring "
                                + executableElement.getSimpleName() + "(" + CanonicalNameConstants.SEEKBAR
                                + " seekBar);");
                valid.invalidate();
            }
        }

    }

    public void hasOnResultMethodParameters(ExecutableElement executableElement, IsValid valid) {
        List<? extends VariableElement> parameters = executableElement.getParameters();
        boolean resultCodeParameterFound = false;
        boolean intentParameterFound = false;
        for (VariableElement parameter : parameters) {
            TypeMirror parameterType = parameter.asType();
            if (parameter.getAnnotation(OnActivityResult.Extra.class) != null) {
                continue;
            }
            if (parameterType.toString().equals(CanonicalNameConstants.INTEGER) //
                    || parameterType.getKind().equals(TypeKind.INT)) {
                if (resultCodeParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type int or java.lang.Integer");
                    valid.invalidate();
                }
                resultCodeParameterFound = true;
                continue;
            }
            if (parameterType.toString().equals(CanonicalNameConstants.INTENT)) {
                if (intentParameterFound) {
                    annotationHelper.printAnnotationError(executableElement,
                            "Unrecognized parameter declaration. you can declare only one parameter of type android.content.Intent");
                    valid.invalidate();
                }
                intentParameterFound = true;
                continue;
            }
            valid.invalidate();
            annotationHelper.printAnnotationError(executableElement,
                    "Unrecognized parameter type. %s can only have a android.content.Intent parameter and/or an Integer parameter");
        }
    }

    public void hasNotMultipleAnnotatedMethodWithSameName(Element element, IsValid valid,
            Class<? extends Annotation> annotation) {
        Set<String> actionNames = new TreeSet<String>();

        List<? extends Element> enclosedElements = element.getEnclosedElements();
        for (Element enclosedElement : enclosedElements) {
            if (enclosedElement.getKind() != ElementKind.METHOD
                    || !annotationHelper.hasOneOfClassAnnotations(enclosedElement, annotation)) {
                continue;
            }

            String enclosedElementName = enclosedElement.getSimpleName().toString();
            if (actionNames.contains(enclosedElementName)) {
                valid.invalidate();
                annotationHelper.printError(enclosedElement,
                        "The " + TargetAnnotationHelper.annotationName(annotation)
                                + " annotated method must have unique name even if the signature is not the same");
            } else {
                actionNames.add(enclosedElementName);
            }
        }
    }

    public void hasRightRegisterAtValueDependingOnEnclosingElement(Element element, IsValid valid) {
        Element enclosingElement = element.getEnclosingElement();
        Receiver.RegisterAt registerAt = element.getAnnotation(Receiver.class).registerAt();

        Map<String, List<Receiver.RegisterAt>> validRegisterAts = new HashMap<String, List<Receiver.RegisterAt>>();
        validRegisterAts.put(CanonicalNameConstants.ACTIVITY, VALID_ACTIVITY_REGISTER_AT);
        validRegisterAts.put(CanonicalNameConstants.SERVICE, VALID_SERVICE_REGISTER_AT);
        validRegisterAts.put(CanonicalNameConstants.FRAGMENT, VALID_FRAGMENT_REGISTER_AT);

        for (Map.Entry<String, List<Receiver.RegisterAt>> validRegisterAt : validRegisterAts.entrySet()) {
            String enclosingType = validRegisterAt.getKey();
            Collection<Receiver.RegisterAt> validRegisterAtValues = validRegisterAt.getValue();
            if (extendsType(enclosingElement, enclosingType) && !validRegisterAtValues.contains(registerAt)) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element, "The parameter registerAt of @Receiver in "
                        + enclosingType + " can only be one of the following values : " + validRegisterAtValues);
            }
        }
    }

    public void hasSupportV4JarIfLocal(Element element, IsValid valid) {
        boolean local = element.getAnnotation(Receiver.class).local();
        if (local) {

            Elements elementUtils = annotationHelper.getElementUtils();
            if (elementUtils.getTypeElement(CanonicalNameConstants.LOCAL_BROADCAST_MANAGER) == null) {
                valid.invalidate();
                annotationHelper.printAnnotationError(element,
                        "To use the LocalBroadcastManager, you MUST include the android-support-v4 jar");
            }
        }
    }

    public void extendsPreferenceActivityOrPreferenceFragment(Element element, IsValid valid) {
        extendsOneOfTypes(element, VALID_PREFERENCE_CLASSES, valid);
    }

    public void extendsPreferenceActivity(Element element, IsValid valid) {
        extendsType(element, CanonicalNameConstants.PREFERENCE_ACTIVITY, valid);
    }

    public void enclosingElementExtendsPreferenceActivityOrPreferenceFragment(Element element, IsValid valid) {
        extendsOneOfTypes(element.getEnclosingElement(), VALID_PREFERENCE_CLASSES, valid);
    }

    public void isPreferenceFragmentClassPresent(Element element, IsValid valid) {
        TypeElement preferenceFragmentElement = annotationHelper.getElementUtils()
                .getTypeElement(CanonicalNameConstants.PREFERENCE_FRAGMENT);

        if (preferenceFragmentElement == null) {
            annotationHelper.printAnnotationError(element, "The class " + CanonicalNameConstants.PREFERENCE_FRAGMENT
                    + " cannot be found. You have to use at least API 11");
        }
    }
}