package org.jboss.resteasy.jsapi; import org.jboss.resteasy.annotations.Form; import org.jboss.resteasy.core.ResourceInvoker; import org.jboss.resteasy.core.ResourceMethodInvoker; import org.jboss.resteasy.jsapi.MethodParamMetaData.MethodParamType; import org.jboss.resteasy.jsapi.i18n.LogMessages; import org.jboss.resteasy.jsapi.i18n.Messages; import org.jboss.resteasy.spi.metadata.ResourceLocator; import org.jboss.resteasy.spi.metadata.ResourceMethod; import org.jboss.resteasy.util.FindAnnotation; import javax.ws.rs.*; import javax.ws.rs.core.Context; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; public class MethodMetaData { private ResourceMethodInvoker invoker; private Method method; private ResourceMethod resourceMethod; private Class<?> klass; private String wants; private String consumesMIMEType; private String uri; private String functionName; private List<MethodParamMetaData> parameters = new ArrayList<MethodParamMetaData>(); private Collection<String> httpMethods; private ServiceRegistry registry; private String functionPrefix; private boolean wantsForm; public MethodMetaData(ServiceRegistry serviceRegistry, ResourceMethodInvoker invoker) throws Exception { this.registry = serviceRegistry; this.invoker = invoker; this.method = invoker.getMethod(); this.resourceMethod = (ResourceMethod) getResourceLocator(invoker); this.klass = invoker.getResourceClass(); String methodPath = resourceMethod.getPath(); String klassPath = resourceMethod.getResourceClass().getPath(); Produces produces = method.getAnnotation(Produces.class); if (produces == null) produces = klass.getAnnotation(Produces.class); this.wants = getWants(produces); Consumes consumes = method.getAnnotation(Consumes.class); if (consumes == null) consumes = klass.getAnnotation(Consumes.class); this.uri = appendURIFragments(registry, klassPath, methodPath); if(serviceRegistry.isRoot()) this.functionPrefix = klass.getSimpleName(); else this.functionPrefix = serviceRegistry.getFunctionPrefix(); this.functionName = this.functionPrefix + "." + method.getName(); httpMethods = invoker.getHttpMethods(); // we need to add all parameters from parent resource locators until the root List<Method> methodsUntilRoot = new ArrayList<Method>(); methodsUntilRoot.add(method); serviceRegistry.collectResourceMethodsUntilRoot(methodsUntilRoot); for (Method method : methodsUntilRoot) { Annotation[][] allAnnotations = method.getParameterAnnotations(); Class<?>[] parameterTypes = method.getParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { processMetaData(parameterTypes[i], allAnnotations[i], true); } } // this must be after we scan the params in case of @Form this.consumesMIMEType = getConsumes(consumes); if(wantsForm && !"application/x-www-form-urlencoded".equals(consumesMIMEType)){ LogMessages.LOGGER.warn(Messages.MESSAGES.overridingConsumes()); this.consumesMIMEType = "application/x-www-form-urlencoded"; } } public static ResourceLocator getResourceLocator(ResourceInvoker invoker) throws Exception { Field resourceMethodField = null; resourceMethodField = invoker.getClass().getDeclaredField("method"); resourceMethodField.setAccessible(true); return (ResourceLocator) resourceMethodField.get(invoker); } protected void processMetaData(Class<?> type, Annotation[] annotations, boolean useBody) { QueryParam query; HeaderParam header; MatrixParam matrix; PathParam uriParam; CookieParam cookie; FormParam formParam; Form form; // boolean isEncoded = FindAnnotation.findAnnotation(annotations, // Encoded.class) != null; if ((query = FindAnnotation.findAnnotation(annotations, QueryParam.class)) != null) { addParameter(type, annotations, MethodParamType.QUERY_PARAMETER, query .value()); } else if ((header = FindAnnotation.findAnnotation(annotations, HeaderParam.class)) != null) { addParameter(type, annotations, MethodParamType.HEADER_PARAMETER, header.value()); } else if ((cookie = FindAnnotation.findAnnotation(annotations, CookieParam.class)) != null) { addParameter(type, annotations, MethodParamType.COOKIE_PARAMETER, cookie.value()); } else if ((uriParam = FindAnnotation.findAnnotation(annotations, PathParam.class)) != null) { addParameter(type, annotations, MethodParamType.PATH_PARAMETER, uriParam.value()); } else if ((matrix = FindAnnotation.findAnnotation(annotations, MatrixParam.class)) != null) { addParameter(type, annotations, MethodParamType.MATRIX_PARAMETER, matrix.value()); } else if ((formParam = FindAnnotation.findAnnotation(annotations, FormParam.class)) != null) { addParameter(type, annotations, MethodParamType.FORM_PARAMETER, formParam.value()); this.wantsForm = true; } else if ((form = FindAnnotation.findAnnotation(annotations, Form.class)) != null) { if (type == Map.class || type == List.class) { addParameter(type, annotations, MethodParamType.FORM, form.prefix()); this.wantsForm = true; } else walkForm(type); } else if ((FindAnnotation.findAnnotation(annotations, Context.class)) != null) { // righfully ignore } else if (useBody) { addParameter(type, annotations, MethodParamType.ENTITY_PARAMETER, null); } } private void walkForm(Class<?> type) { for (Field field : type.getDeclaredFields()) { processMetaData(field.getType(), field.getAnnotations(), false); } for (Method method : type.getDeclaredMethods()) { if (method.getParameterTypes().length != 1 || !method.getReturnType().equals(Void.class)) continue; processMetaData(method.getParameterTypes()[0], method.getAnnotations(), false); } if (type.getSuperclass() != null) { walkForm(type.getSuperclass()); } } private void addParameter(Class<?> type, Annotation[] annotations, MethodParamType paramType, String value) { this.parameters.add(new MethodParamMetaData(type, annotations, paramType, value)); } private String getWants(Produces produces) { if (produces == null) return null; String[] value = produces.value(); if (value.length == 0) return null; if (value.length == 1) return value[0]; StringBuffer buf = new StringBuffer(); for (String mime : produces.value()) { if (buf.length() != 0) buf.append(","); buf.append(mime); } return buf.toString(); } private String getConsumes(Consumes consumes) { if (consumes == null) return "text/plain"; if (consumes.value().length > 0) return consumes.value()[0]; return "text/plain"; } public static String appendURIFragments(ServiceRegistry registry, String classPath, String methodPath) { return appendURIFragments(registry == null ? null : registry.getUri(), notEmpty(classPath) ? classPath : null, notEmpty(methodPath) ? methodPath : null); } public static String appendURIFragments(String... fragments) { StringBuilder str = new StringBuilder(); for (String fragment : fragments) { if (fragment == null || fragment.length() == 0 || fragment.equals("/")) continue; if (fragment.startsWith("/")) fragment = fragment.substring(1); if (fragment.endsWith("/")) fragment = fragment.substring(0, fragment.length() - 1); str.append('/').append(fragment); } if (str.length() == 0) return "/"; return str.toString(); } public ResourceMethodInvoker getInvoker() { return invoker; } public Method getMethod() { return method; } public Class<?> getKlass() { return klass; } public String getWants() { return wants; } public String getConsumesMIMEType() { return consumesMIMEType; } public String getUri() { return uri; } public String getFunctionName() { return functionName; } public List<MethodParamMetaData> getParameters() { return parameters; } public Collection<String> getHttpMethods() { return httpMethods; } private static boolean notEmpty(String string) { return string != null && !string.isEmpty(); } public String getFunctionPrefix() { return functionPrefix; } }