/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (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.civilian-framework.org/license.txt * * 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.civilian.internal.controller; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Comparator; import org.civilian.annotation.Consumes; import org.civilian.annotation.Path; import org.civilian.annotation.Produces; import org.civilian.annotation.RequestMethod; import org.civilian.content.ContentType; import org.civilian.content.ContentTypeList; import org.civilian.util.ClassUtil; /** * Helper class to extract annotated information from a controller action method. */ public class MethodAnnotations { /** * Returns a method annotations object for a controller action method, or * null if the method is not a action method. */ public static MethodAnnotations create(Method javaMethod) { int mod = javaMethod.getModifiers(); if (Modifier.isPublic(mod) && !Modifier.isStatic(mod) && (javaMethod.getReturnType() == void.class)) { MethodAnnotations ma = new MethodAnnotations(javaMethod); if (ma.isActionMethod()) return ma; } return null; } /** * Returns the value of {@link Path} annotation of a controller action method * or null if the method has no path annotation or is not a action method. */ public static String getPath(Method javaMethod) { Path pathAnno = javaMethod.getAnnotation(Path.class); if (pathAnno != null) { String path = pathAnno.value(); // ignore path's with length 0 if ((path.length() > 0) && (create(javaMethod) != null)) return path; } return null; } public MethodAnnotations(Method javaMethod) { list_ = new AntnList(javaMethod); ArrayList<String> reqMethods = list_.addRequestMethods(null); if (reqMethods != null) reqMethods.toArray(requestMethods_ = new String[reqMethods.size()]); } public boolean isActionMethod() { return requestMethods_ != null; } public String[] getRequestMethods() { return requestMethods_; } public ContentTypeList getProduces() { ContentTypeList produces = null; Produces annotation = list_.getAnnotation(Produces.class); if (annotation != null) { // we sort by specificity to speed up content negotiation produces = extractContentTypes(ContentType.Compare.BY_SPECIFICITY, annotation.value()); } return produces; } public ContentTypeList getConsumes() { ContentTypeList consumes = null; Consumes annotation = list_.getAnnotation(Consumes.class); if (annotation != null) consumes = extractContentTypes(null, annotation.value()); return consumes; } private ContentTypeList extractContentTypes(Comparator<ContentType> comparator, String[] p) { ContentTypeList list = ContentTypeList.parse(comparator, p); return list.size() == 0 ? null : list; } private class AntnList { public AntnList(Method javaMethod) { this(javaMethod, javaMethod.getParameterTypes()); } private AntnList(Method javaMethod, Class<?>[] paramTypes) { javaMethod_ = javaMethod; annotations_ = javaMethod.getAnnotations(); Method superMethod = findOverwrittenMethod(javaMethod.getName(), paramTypes, javaMethod.getDeclaringClass().getSuperclass()); next_ = superMethod != null ? new AntnList(superMethod, paramTypes) : null; } private Method findOverwrittenMethod(String methodName, Class<?>[] paramTypes, Class<?> c) { while(c != null) { try { return c.getDeclaredMethod(methodName, paramTypes); } catch (NoSuchMethodException e) { c = c.getSuperclass(); } } return null; } public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { T annotation = javaMethod_.getAnnotation(annotationClass); if ((annotation == null) && (next_ != null)) annotation = next_.getAnnotation(annotationClass); return annotation; } public ArrayList<String> addRequestMethods(ArrayList<String> list) { for (Annotation annotation : annotations_) list = addRequestMethods(annotation, list); if ((list == null) && (next_ != null)) list = next_.addRequestMethods(null); return list; } private ArrayList<String> addRequestMethods(Annotation annotation, ArrayList<String> list) { if (annotation != null) { if (ClassUtil.isA(annotation, RequestMethod.class)) list = addRequestMethods(list, ((RequestMethod)annotation).value()); else list = addRequestMethods(annotation.annotationType().getAnnotation(RequestMethod.class), list); } return list; } private ArrayList<String> addRequestMethods(ArrayList<String> list, String... methods) { if (list == null) list = new ArrayList<>(); for (String method : methods) { if (!list.contains(method)) list.add(method); } return list; } private final Method javaMethod_; private final Annotation[] annotations_; private final AntnList next_; } private AntnList list_; private String[] requestMethods_; }