
fathom.rest.controller.ControllerScanner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fathom-rest Show documentation
Show all versions of fathom-rest Show documentation
RESTful Routes and Controllers based on Pippo
/*
* Copyright (C) 2015 the original author or authors.
*
* 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 fathom.rest.controller;
import com.google.common.collect.Sets;
import fathom.conf.Settings;
import fathom.utils.ClassUtil;
import fathom.utils.RequireUtil;
import fathom.utils.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Base class for identifying annotated controllers.
*
* @author James Moger
*/
public abstract class ControllerScanner {
private static final Logger log = LoggerFactory.getLogger(ControllerScanner.class);
protected final Settings settings;
protected final Set> httpMethodAnnotationClasses = Sets.newHashSet(DELETE.class, GET
.class, HEAD.class, OPTIONS.class, PATCH.class, POST.class, PUT.class);
protected ControllerScanner(Settings settings) {
this.settings = settings;
}
/**
* Discover Controller classes.
*
* @param packageNames
* @return controller classes
*/
protected Collection> discoverClasses(String... packageNames) {
log.debug("Discovering annotated controller in package(s) '{}'", Arrays.toString(packageNames));
Collection> classes = ClassUtil.getAnnotatedClasses(Path.class, packageNames);
return classes;
}
/**
* Discover Route methods.
*
* @param classes
* @return discovered methods
*/
protected Map> discoverMethods(Collection> classes) {
// collect the allowed annotated methods
Map> discoveredMethods = new LinkedHashMap<>();
// discover all annotated controllers and methods
for (Class> controllerClass : classes) {
for (Method method : controllerClass.getDeclaredMethods()) {
if (RequireUtil.allowMethod(settings, method)) {
for (Annotation annotation : method.getAnnotations()) {
Class extends Annotation> annotationClass = annotation.annotationType();
if (httpMethodAnnotationClasses.contains(annotationClass)) {
discoveredMethods.put(method, annotationClass);
break;
}
}
}
}
}
return discoveredMethods;
}
/**
* Sort the methods by their preferred order, if specified.
*
* @param methods
* @return a sorted list of methods
*/
protected Collection sortMethods(Collection methods) {
List list = new ArrayList<>(methods);
Collections.sort(list, (m1, m2) -> {
int o1 = Integer.MAX_VALUE;
Order order1 = ClassUtil.getAnnotation(m1, Order.class);
if (order1 != null) {
o1 = order1.value();
}
int o2 = Integer.MAX_VALUE;
Order order2 = ClassUtil.getAnnotation(m2, Order.class);
if (order2 != null) {
o2 = order2.value();
}
if (o1 == o2) {
// same or unsorted, compare controller+method
String s1 = Util.toString(m1);
String s2 = Util.toString(m2);
return s1.compareTo(s2);
}
if (o1 < o2) {
return -1;
} else {
return 1;
}
});
return list;
}
/**
* Recursively builds the paths for the controller class.
*
* @param controllerClass
* @return the paths for the controller
*/
protected Set collectPaths(Class> controllerClass) {
Set parentPaths = Collections.emptySet();
if (controllerClass.getSuperclass() != null) {
parentPaths = collectPaths(controllerClass.getSuperclass());
}
Set paths = new LinkedHashSet<>();
Path controllerPath = controllerClass.getAnnotation(Path.class);
if (controllerPath != null && controllerPath.value().length > 0) {
if (parentPaths.isEmpty()) {
// add all controller paths
paths.addAll(Arrays.asList(controllerPath.value()));
} else {
// create controller paths based on the parent paths
for (String parentPath : parentPaths) {
for (String path : controllerPath.value()) {
paths.add(parentPath + path);
}
}
}
} else {
// add all parent paths
paths.addAll(parentPaths);
}
return paths;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy