blob: 47d07a1a01e5077d77f54fdf334ae4de78865b7c [file] [log] [blame]
// ***************************************************************************************************************************
// * 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;
import static org.apache.juneau.internal.ConsumerUtils.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.function.*;
import org.apache.juneau.internal.*;
/**
* Interface that provides the ability to look up annotations on classes/methods/constructors/fields.
*
* <h5 class='section'>See Also:</h5><ul>
* </ul>
*/
public interface AnnotationProvider {
/**
* Disable annotation caching.
*/
boolean DISABLE_ANNOTATION_CACHING = Boolean.getBoolean("juneau.disableAnnotationCaching");
/**
* Default metadata provider.
*/
@SuppressWarnings("unchecked") AnnotationProvider DEFAULT = new AnnotationProvider() {
private final TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,Annotation[]> classAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, Class::getAnnotationsByType);
private final TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,Annotation[]> declaredClassAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, Class::getDeclaredAnnotationsByType);
private final TwoKeyConcurrentCache<Method,Class<? extends Annotation>,Annotation[]> methodAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, Method::getAnnotationsByType);
private final TwoKeyConcurrentCache<Field,Class<? extends Annotation>,Annotation[]> fieldAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, Field::getAnnotationsByType);
private final TwoKeyConcurrentCache<Constructor<?>,Class<? extends Annotation>,Annotation[]> constructorAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING, Constructor::getAnnotationsByType);
@Override /* MetaProvider */
public <A extends Annotation> void forEachAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action) {
if (type != null && onClass != null)
for (A a : annotations(type, onClass))
consume(filter, action, a);
}
@Override /* MetaProvider */
public <A extends Annotation> A firstAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
if (type != null && onClass != null)
for (A a : annotations(type, onClass))
if (test(filter, a))
return a;
return null;
}
@Override /* MetaProvider */
public <A extends Annotation> A lastAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
A x = null;
if (type != null && onClass != null)
for (A a : annotations(type, onClass))
if (test(filter, a))
x = a;
return x;
}
@Override /* MetaProvider */
public <A extends Annotation> void forEachDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action) {
if (type != null && onClass != null)
for (A a : declaredAnnotations(type, onClass))
consume(filter, action, a);
}
@Override /* MetaProvider */
public <A extends Annotation> A firstDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
if (type != null && onClass != null)
for (A a : declaredAnnotations(type, onClass))
if (test(filter, a))
return a;
return null;
}
@Override /* MetaProvider */
public <A extends Annotation> A lastDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) {
A x = null;
if (type != null && onClass != null)
for (A a : declaredAnnotations(type, onClass))
if (test(filter, a))
x = a;
return x;
}
@Override /* MetaProvider */
public <A extends Annotation> void forEachAnnotation(Class<A> type, Method onMethod, Predicate<A> filter, Consumer<A> action) {
if (type != null && onMethod != null)
for (A a : annotations(type, onMethod))
consume(filter, action, a);
}
@Override /* MetaProvider */
public <A extends Annotation> A firstAnnotation(Class<A> type, Method onMethod, Predicate<A> filter) {
if (type != null && onMethod != null)
for (A a : annotations(type, onMethod))
if (test(filter, a))
return a;
return null;
}
@Override /* MetaProvider */
public <A extends Annotation> A lastAnnotation(Class<A> type, Method onMethod, Predicate<A> filter) {
A x = null;
if (type != null && onMethod != null)
for (A a : annotations(type, onMethod))
if (test(filter, a))
x = a;
return x;
}
@Override /* MetaProvider */
public <A extends Annotation> void forEachAnnotation(Class<A> type, Field onField, Predicate<A> filter, Consumer<A> action) {
if (type != null && onField != null)
for (A a : annotations(type, onField))
consume(filter, action, a);
}
@Override /* MetaProvider */
public <A extends Annotation> A firstAnnotation(Class<A> type, Field onField, Predicate<A> filter) {
if (type != null && onField != null)
for (A a : annotations(type, onField))
if (test(filter, a))
return a;
return null;
}
@Override /* MetaProvider */
public <A extends Annotation> A lastAnnotation(Class<A> type, Field onField, Predicate<A> filter) {
A x = null;
if (type != null && onField != null)
for (A a : annotations(type, onField))
if (test(filter, a))
x = a;
return x;
}
@Override /* MetaProvider */
public <A extends Annotation> void forEachAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter, Consumer<A> action) {
if (type != null && onConstructor != null)
for (A a : annotations(type, onConstructor))
consume(filter, action, a);
}
@Override /* MetaProvider */
public <A extends Annotation> A firstAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter) {
if (type != null && onConstructor != null)
for (A a : annotations(type, onConstructor))
if (test(filter, a))
return a;
return null;
}
@Override /* MetaProvider */
public <A extends Annotation> A lastAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter) {
A x = null;
if (type != null && onConstructor != null)
for (A a : annotations(type, onConstructor))
if (test(filter, a))
x = a;
return x;
}
private <A extends Annotation> A[] annotations(Class<A> type, Class<?> onClass) {
return (A[])classAnnotationCache.get(onClass, type);
}
private <A extends Annotation> A[] declaredAnnotations(Class<A> type, Class<?> onClass) {
return (A[])declaredClassAnnotationCache.get(onClass, type);
}
private <A extends Annotation> A[] annotations(Class<A> type, Method onMethod) {
return (A[])methodAnnotationCache.get(onMethod, type);
}
private <A extends Annotation> A[] annotations(Class<A> type, Field onField) {
return (A[])fieldAnnotationCache.get(onField, type);
}
private <A extends Annotation> A[] annotations(Class<A> type, Constructor<?> onConstructor) {
return (A[])constructorAnnotationCache.get(onConstructor, type);
}
};
/**
* Performs an action on the matching annotations on the specified class.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onClass The class to search on.
* @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>.
* @param action An action to perform on the entry.
*/
<A extends Annotation> void forEachAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action);
/**
* Finds the first matching annotation on the specified class.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onClass The class to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if not found.
*/
<A extends Annotation> A firstAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter);
/**
* Finds the last matching annotation on the specified class.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onClass The class to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if not found.
*/
<A extends Annotation> A lastAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter);
/**
* Performs an action on the matching declared annotations on the specified class.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onClass The class to search on.
* @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>.
* @param action An action to perform on the entry.
*/
<A extends Annotation> void forEachDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action);
/**
* Finds the first matching declared annotations on the specified class.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onClass The class to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A firstDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter);
/**
* Finds the last matching declared annotations on the specified class.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onClass The class to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A lastDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter);
/**
* Performs an action on the matching annotations on the specified method.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onMethod The method to search on.
* @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>.
* @param action An action to perform on the entry.
*/
<A extends Annotation> void forEachAnnotation(Class<A> type, Method onMethod, Predicate<A> filter, Consumer<A> action);
/**
* Finds the first matching annotation on the specified method.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onMethod The method to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A firstAnnotation(Class<A> type, Method onMethod, Predicate<A> filter);
/**
* Finds the last matching annotation on the specified method.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onMethod The method to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A lastAnnotation(Class<A> type, Method onMethod, Predicate<A> filter);
/**
* Performs an action on the matching annotations on the specified field.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onField The field to search on.
* @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>.
* @param action An action to perform on the entry.
*/
<A extends Annotation> void forEachAnnotation(Class<A> type, Field onField, Predicate<A> filter, Consumer<A> action);
/**
* Finds the first matching annotation on the specified field.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onField The field to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A firstAnnotation(Class<A> type, Field onField, Predicate<A> filter);
/**
* Finds the last matching annotation on the specified field.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onField The field to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A lastAnnotation(Class<A> type, Field onField, Predicate<A> filter);
/**
* Performs an action on the matching annotations on the specified constructor.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onConstructor The constructor to search on.
* @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>.
* @param action An action to perform on the entry.
*/
<A extends Annotation> void forEachAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter, Consumer<A> action);
/**
* Finds the first matching annotation on the specified constructor.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onConstructor The constructor to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A firstAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter);
/**
* Finds the last matching annotation on the specified constructor.
*
* @param <A> The annotation type to find.
* @param type The annotation type to find.
* @param onConstructor The constructor to search on.
* @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>.
* @return The matched annotation, or <jk>null</jk> if no annotations matched.
*/
<A extends Annotation> A lastAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter);
}