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

io.permazen.AnnotationScanner Maven / Gradle / Ivy

There is a newer version: 5.1.0
Show newest version

/*
 * Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
 */

package io.permazen;

import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;

import org.dellroad.stuff.java.MethodAnnotationScanner;

/**
 * Support superclass for Java model class annotation scanners.
 */
abstract class AnnotationScanner extends MethodAnnotationScanner {

    /**
     * The associated Java model class, if any.
     */
    protected final JClass jclass;

    /**
     * Constructor for when there is an associated {@link JClass}.
     *
     * @param jclass Java model class
     * @param annotationType annotation to scan for
     */
    protected AnnotationScanner(JClass jclass, Class annotationType) {
        super(jclass.getType(), annotationType);
        this.jclass = jclass;
    }

    /**
     * Constructor for when there is no associated {@link JClass}.
     *
     * @param type Java type to scan
     * @param annotationType annotation to scan for
     */
    @SuppressWarnings("unchecked")
    protected AnnotationScanner(Class type, Class annotationType) {
        super(type, annotationType);
        this.jclass = null;
    }

    /**
     * Get the annotation on the given method.
     *
     * 

* Utilizes {@link Util#getAnnotation Util.getAnnotation()}. * * @return the annotation found, or null if not found */ @Override protected A getAnnotation(Method method) { return Util.getAnnotation(method, this.annotationType); } /** * Get a simple description of the annotation being scanned for. * * @return annotation description */ public String getAnnotationDescription() { return "@" + this.annotationType.getSimpleName(); } /** * Verify method is not static. * * @param method the method to check * @throws IllegalArgumentException if method is static */ protected void checkNotStatic(Method method) { if ((method.getModifiers() & Modifier.STATIC) != 0) throw new IllegalArgumentException(this.getErrorPrefix(method) + "annotation is not supported on static methods"); } /** * Verify method return type. * * @param method the method to check * @param expecteds allowed return types * @throws IllegalArgumentException if has an invalid return type */ protected void checkReturnType(Method method, List> expecteds) { final TypeToken actual = TypeToken.of(method.getGenericReturnType()); for (TypeToken expected : expecteds) { if (actual.equals(expected)) return; } throw new IllegalArgumentException(this.getErrorPrefix(method) + "method is required to return " + (expecteds.size() != 1 ? "one of " + expecteds : expecteds.get(0)) + " but instead returns " + actual); } /** * Verify method return type. * * @param method the method to check * @param expecteds allowed return types * @throws IllegalArgumentException if has an invalid return type */ protected void checkReturnType(Method method, Class... expecteds) { final Class actual = method.getReturnType(); for (Class expected : expecteds) { if (actual.equals(expected)) return; } throw new IllegalArgumentException(this.getErrorPrefix(method) + "method is required to return " + (expecteds.length != 1 ? "one of " + Arrays.asList(expecteds) : expecteds[0]) + " but instead returns " + actual); } /** * Verify method parameter type(s). * * @param method the method to check * @param expected expected parameter types * @throws IllegalArgumentException if has an invalid parameter type(s) */ protected void checkParameterTypes(Method method, List> expected) { final List> actual = this.getParameterTypeTokens(method); if (!actual.equals(expected)) { throw new IllegalArgumentException(this.getErrorPrefix(method) + "method is required to take " + (expected.isEmpty() ? "zero parameters" : expected.size() + " parameter(s) of type " + expected)); } } /** * Verify method parameter type(s). * * @param method the method to check * @param expected expected parameter types * @throws IllegalArgumentException if has an invalid parameter type(s) */ protected void checkParameterTypes(Method method, TypeToken... expected) { this.checkParameterTypes(method, Arrays.asList(expected)); } /** * Verify a specific method parameter's type. * * @param method the method to check * @param index parameter index * @param choices allowed parameter types * @throws IllegalArgumentException if parameter type does not match */ protected void checkParameterType(Method method, int index, List> choices) { final List> actuals = this.getParameterTypeTokens(method); if (actuals.size() <= index || !choices.contains(actuals.get(index))) { throw new IllegalArgumentException(this.getErrorPrefix(method) + "method parameter #" + (index + 1) + " is required to have type " + (choices.size() != 1 ? "one of " + choices : choices.get(0))); } } /** * Verify a specific method parameter's type. * * @param method the method to check * @param index parameter index * @param choices allowed parameter types * @throws IllegalArgumentException if parameter type does not match */ protected void checkParameterType(Method method, int index, TypeToken... choices) { this.checkParameterType(method, index, Arrays.asList(choices)); } /** * Verify method takes a single parameter of the specified type. * * @param method the method to check * @param choices allowed parameter types * @throws IllegalArgumentException if parameter type does not match */ protected void checkSingleParameterType(Method method, List> choices) { final List> actuals = this.getParameterTypeTokens(method); if (actuals.size() != 1 || !choices.contains(actuals.get(0))) { throw new IllegalArgumentException(this.getErrorPrefix(method) + "method is required to take a single parameter" + " with type " + (choices.size() != 1 ? "one of " + choices : choices.get(0))); } } /** * Get method parameter types as {@link TypeToken}s. * * @param method the method to check * @return method parameter types */ protected List> getParameterTypeTokens(Method method) { return Lists.transform(Arrays.asList(method.getGenericParameterTypes()), TypeToken::of); } /** * Get "invalid annotation" error message prefix that describes the annotation on the specified method. * * @param method the method to check * @return error message prefix */ protected String getErrorPrefix(Method method) { return "invalid " + this.getAnnotationDescription() + " annotation on method " + method + " for type `" + this.jclass.getName() + "': "; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy