Java tutorial
/* * Copyright (c) 2014 Andrey Paslavsky. * * 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 net.paslavsky.springrest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; /** * TODO Class description * * @author Andrey Paslavsky * @version 1.0 */ public class SpringAnnotationPreprocessor implements AnnotationPreprocessor { private final Logger logger = LoggerFactory.getLogger(getClass()); @Override public RestMethodMetadata parse(Class<?> clientClass, Method method) { RestMethodMetadata metadata = new RestMethodMetadata(); RequestMapping classMapping = clientClass.getAnnotation(RequestMapping.class); RequestMapping methodMapping = method.getAnnotation(RequestMapping.class); metadata.setCommonPath(getPath(classMapping)); metadata.setAdditionalPath(getPath(methodMapping)); metadata.setHttpMethod(getHttpMethod(classMapping, methodMapping)); metadata.setResponseClass(getResponseType(method)); metadata.setMethodReturnType(method.getReturnType()); metadata.setRequestHeaderParameters(getParametersWithAnnotation(method, RequestHeader.class)); metadata.setUriVarParameters(getParametersWithAnnotation(method, PathVariable.class)); metadata.setQueryParameters(getParametersWithAnnotation(method, RequestParam.class)); metadata.setRequestParameter(getRequestParameter(method)); return metadata; } private Integer getRequestParameter(Method method) { Integer requestParameter = null; Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0, parameterAnnotationsLength = parameterAnnotations.length; i < parameterAnnotationsLength; i++) { Annotation[] annotations = parameterAnnotations[i]; if (isAnnotationPresent(annotations, RequestBody.class)) { requestParameter = i; } } return requestParameter; } private String getPath(RequestMapping classMapping) { if (classMapping != null && isNotEmpty(classMapping.value())) { return classMapping.value()[0]; } return null; } private static <T> boolean isNotEmpty(T[] array) { return array != null && array.length > 0; } private HttpMethod getHttpMethod(RequestMapping classMapping, RequestMapping methodMapping) { HttpMethod httpMethod; if (methodMapping != null && isNotEmpty(methodMapping.method())) { httpMethod = getHttpMethod(methodMapping); } else if (classMapping != null && isNotEmpty(classMapping.method())) { httpMethod = getHttpMethod(classMapping); } else { // TODO add warning to the logs throw new SpringRestClientConfigurationException("Can't identify HTTP method!"); } return httpMethod; } private HttpMethod getHttpMethod(RequestMapping mapping) { return HttpMethod.valueOf(mapping.method()[0].name()); } private Class<?> getResponseType(Method method) { Class<?> type = getResponseType0(method); if (type == Object.class) { logger.warn("REST client can't identify response type of the method {}.", method); logger.warn("Response will be returned as byte array", new RuntimeException()); return byte[].class; } return type; } private Class<?> getResponseType0(Method method) { if (method.isAnnotationPresent(ResponseBody.class)) { return method.getReturnType(); } else { if (method.getReturnType() == ResponseEntity.class) { Type methodGenericReturnType = method.getGenericReturnType(); if (methodGenericReturnType instanceof ParameterizedTypeImpl) { ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) methodGenericReturnType; Type type = parameterizedType.getActualTypeArguments()[0]; return typeToClass(type); } else { // TODO Message to the log: recommendation to use ResponseEntity with generic parameter return byte[].class; } } return Void.class; } } private Class<?> typeToClass(Type type) { if (type instanceof ParameterizedTypeImpl) { return ((ParameterizedTypeImpl) type).getRawType(); } else { return (Class) type; } } private Map<String, Integer> getParametersWithAnnotation(Method method, Class<? extends Annotation> annotationClass) { Map<String, Integer> parameters = new HashMap<String, Integer>(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0; i < parameterAnnotations.length; i++) { Annotation[] annotations = parameterAnnotations[i]; if (isAnnotationPresent(annotations, annotationClass)) { String name = getValue(annotations, annotationClass); if (StringUtils.isEmpty(name)) { throw new SpringRestClientConfigurationException( "REST client can't identify name by " + annotationClass); } parameters.put(name, i); } } return parameters; } private boolean isAnnotationPresent(Annotation[] annotations, Class<? extends Annotation> annotationClass) { for (Annotation annotation : annotations) { if (annotationClass.isInstance(annotation)) { return true; } } return false; } private String getValue(Annotation[] annotations, Class<? extends Annotation> annotationClass) { for (Annotation annotation : annotations) { if (annotationClass.isInstance(annotation)) { Method valueMethod = ReflectionUtils.findMethod(annotationClass, "value"); if (valueMethod != null) { return (String) ReflectionUtils.invokeMethod(valueMethod, annotation); } else { return null; } } } return null; } }