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

org.apache.juneau.reflect.ParamInfo Maven / Gradle / Ivy

// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you 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.apache.juneau.reflect;

import static org.apache.juneau.internal.CollectionUtils.*;
import static org.apache.juneau.internal.ConsumerUtils.*;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;

import org.apache.juneau.*;
import org.apache.juneau.annotation.*;

/**
 * Lightweight utility class for introspecting information about a method parameter.
 *
 * 
See Also:
    *
*/ public final class ParamInfo { private final ExecutableInfo eInfo; private final Parameter p; private final int index; private volatile Map,Optional> annotationMap; //----------------------------------------------------------------------------------------------------------------- // Instantiation //----------------------------------------------------------------------------------------------------------------- /** * Constructor. * * @param eInfo The constructor or method wrapper. * @param p The parameter being wrapped. * @param index The parameter index. */ protected ParamInfo(ExecutableInfo eInfo, Parameter p, int index) { this.eInfo = eInfo; this.p = p; this.index = index; } /** * Returns the index position of this parameter. * * @return The index position of this parameter. */ public int getIndex() { return index; } /** * Returns the method that this parameter belongs to. * * @return The method that this parameter belongs to, or null if it belongs to a constructor. */ public MethodInfo getMethod() { return eInfo.isConstructor() ? null : (MethodInfo)eInfo; } /** * Returns the constructor that this parameter belongs to. * * @return The constructor that this parameter belongs to, or null if it belongs to a method. */ public ConstructorInfo getConstructor() { return eInfo.isConstructor() ? (ConstructorInfo)eInfo : null; } /** * Returns the class type of this parameter. * * @return The class type of this parameter. */ public ClassInfo getParameterType() { return eInfo.getParamType(index); } //----------------------------------------------------------------------------------------------------------------- // Annotations //----------------------------------------------------------------------------------------------------------------- /** * Performs an action on all matching annotations declared on this parameter. * * @param The annotation type to look for. * @param type The annotation type to look for. * @param filter A predicate to apply to the entries to determine if action should be performed. Can be null. * @param action An action to perform on the entry. * @return This object. */ public ParamInfo forEachDeclaredAnnotation(Class type, Predicate filter, Consumer action) { for (Annotation a : eInfo._getParameterAnnotations(index)) consume(type, filter, action, a); return this; } /** * Returns the specified parameter annotation declared on this parameter. * * @param The annotation type to look for. * @param type The annotation type to look for. * @return The specified parameter annotation declared on this parameter, or null if not found. */ public A getDeclaredAnnotation(Class type) { if (type != null) for (Annotation a : eInfo._getParameterAnnotations(index)) if (type.isInstance(a)) return type.cast(a); return null; } /** * Finds the annotation of the specified type defined on this method parameter. * *

* If the annotation cannot be found on the immediate method, searches methods with the same * signature on the parent classes or interfaces. *
The search is performed in child-to-parent order. * *

* If still not found, searches for the annotation on the return type of the method. * * @param The annotation type to look for. * @param type The annotation type to look for. * @return * The annotation if found, or null if not. */ @SuppressWarnings("unchecked") public A getAnnotation(Class type) { Optional o = annotationMap().get(type); if (o == null) { o = optional(findAnnotation(type)); annotationMap().put(type, o); } return o.isPresent() ? (A)o.get() : null; } /** * Returns true if this parameter has the specified annotation. * * @param The annotation type to look for. * @param type The annotation type to look for. * @return * The true if annotation if found. */ public boolean hasAnnotation(Class type) { return getAnnotation(type) != null; } /** * Returns true if this parameter doesn't have the specified annotation. * * @param The annotation type to look for. * @param type The annotation type to look for. * @return * The true if annotation if not found. */ public boolean hasNoAnnotation(Class type) { return ! hasAnnotation(type); } private A findAnnotation(Class type) { if (eInfo.isConstructor()) { for (Annotation a2 : eInfo._getParameterAnnotations(index)) if (type.isInstance(a2)) return type.cast(a2); return eInfo.getParamType(index).unwrap(Value.class,Optional.class).getAnnotation(type); } MethodInfo mi = (MethodInfo)eInfo; Value v = Value.empty(); mi.forEachMatchingParentFirst(x -> true, x -> x.forEachParameterAnnotation(index, type, y -> true, y -> v.set(y))); return v.orElseGet(() -> eInfo.getParamType(index).unwrap(Value.class,Optional.class).getAnnotation(type)); } /** * Performs an action on all matching annotations on this parameter. * *

* Searches all methods with the same signature on the parent classes or interfaces * and the return type on the method. *

* Results are in parent-to-child order. * * @param The annotation type to look for. * @param type The annotation type to look for. * @param filter A predicate to apply to the entries to determine if action should be performed. Can be null. * @param action An action to perform on the entry. * @return This object. */ public ParamInfo forEachAnnotation(Class type, Predicate filter, Consumer action) { return forEachAnnotation(AnnotationProvider.DEFAULT, type, filter, action); } /** * Returns the first matching annotation on this method parameter. * *

* Searches all methods with the same signature on the parent classes or interfaces * and the return type on the method. *

* Results are in parent-to-child order. * * @param The annotation type to look for. * @param type The annotation type to look for. * @param filter A predicate to apply to the entries to determine if value should be used. Can be null. * @return A list of all matching annotations found or an empty list if none found. */ @SuppressWarnings("unchecked") public A getAnnotation(Class type, Predicate filter) { if (eInfo.isConstructor) { ClassInfo ci = eInfo.getParamType(index).unwrap(Value.class,Optional.class); A o = ci.getAnnotation(type, filter); if (o != null) return o; for (Annotation a2 : eInfo._getParameterAnnotations(index)) if (test(type, filter, a2)) return (A)a2; } else { MethodInfo mi = (MethodInfo)eInfo; ClassInfo ci = eInfo.getParamType(index).unwrap(Value.class,Optional.class); A o = ci.getAnnotation(type, filter); if (o != null) return o; Value v = Value.empty(); mi.forEachMatchingParentFirst(x -> true, x -> x.forEachParameterAnnotation(index, type, filter, y -> v.set(y))); return v.orElse(null); } return null; } private ParamInfo forEachAnnotation(AnnotationProvider ap, Class a, Predicate filter, Consumer action) { if (eInfo.isConstructor) { ClassInfo ci = eInfo.getParamType(index).unwrap(Value.class,Optional.class); Annotation[] annotations = eInfo._getParameterAnnotations(index); ci.forEachAnnotation(ap, a, filter, action); for (Annotation a2 : annotations) consume(a, filter, action, a2); } else { MethodInfo mi = (MethodInfo)eInfo; ClassInfo ci = eInfo.getParamType(index).unwrap(Value.class,Optional.class); ci.forEachAnnotation(ap, a, filter, action); mi.forEachMatchingParentFirst(x -> true, x -> x.forEachParameterAnnotation(index, a, filter, action)); } return this; } private Map,Optional> annotationMap() { if (annotationMap == null) { synchronized(this) { annotationMap = new ConcurrentHashMap<>(); } } return annotationMap; } //----------------------------------------------------------------------------------------------------------------- // Other methods //----------------------------------------------------------------------------------------------------------------- /** * Returns true if this object passes the specified predicate test. * * @param test The test to perform. * @return true if this object passes the specified predicate test. */ public boolean matches(Predicate test) { return test(test, this); } /** * Performs an action on this object if the specified predicate test passes. * * @param test A test to apply to determine if action should be executed. Can be null. * @param action An action to perform on this object. * @return This object. */ public ParamInfo accept(Predicate test, Consumer action) { if (matches(test)) action.accept(this); return this; } /** * Returns true if the parameter type is an exact match for the specified class. * * @param c The type to check. * @return true if the parameter type is an exact match for the specified class. */ public boolean isType(Class c) { return getParameterType().is(c); } /** * Returns true if the parameter has a name provided by the class file. * * @return true if the parameter has a name provided by the class file. */ public boolean hasName() { return p.isNamePresent() || p.isAnnotationPresent(Name.class); } /** * Returns the name of the parameter. * *

* If the parameter's name is present, then this method returns the name provided by the class file. * Otherwise, this method synthesizes a name of the form argN, where N is the index of the parameter in the descriptor of the method which declares the parameter. * * @return The name of the parameter. * @see Parameter#getName() */ public String getName() { Name n = p.getAnnotation(Name.class); if (n != null) return n.value(); if (p.isNamePresent()) return p.getName(); return null; } /** * Returns true if this parameter can accept the specified value. * * @param value The value to check. * @return true if this parameter can accept the specified value. */ public boolean canAccept(Object value) { return getParameterType().isInstance(value); } @Override public String toString() { return (eInfo.getSimpleName()) + "[" + index + "]"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy