Repository: incubator-juneau Updated Branches: refs/heads/master 321f6bdee -> d6fe4ff9d
Support for more REST method parameter types. Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/d6fe4ff9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/d6fe4ff9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/d6fe4ff9 Branch: refs/heads/master Commit: d6fe4ff9d96f070b4b0b93ad740b2ab7afdcfba2 Parents: 321f6bd Author: JamesBognar <[email protected]> Authored: Sun May 7 17:16:00 2017 -0400 Committer: JamesBognar <[email protected]> Committed: Sun May 7 17:16:00 2017 -0400 ---------------------------------------------------------------------- .../org/apache/juneau/internal/ClassUtils.java | 13 ++ .../java/org/apache/juneau/rest/CallMethod.java | 218 +++++++------------ .../java/org/apache/juneau/rest/RestParam.java | 22 +- 3 files changed, 106 insertions(+), 147 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/d6fe4ff9/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java b/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java index 39bf16b..1f2788b 100644 --- a/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java +++ b/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java @@ -145,6 +145,19 @@ public final class ClassUtils { } /** + * Returns <jk>true</jk> if <code>parent</code> is a parent class or the same as <code>child</code>. + * + * @param parent The parent class. + * @param child The child class. + * @return <jk>true</jk> if <code>parent</code> is a parent class or the same as <code>child</code>. + */ + public static boolean isParentClass(Class<?> parent, Type child) { + if (child instanceof Class) + return isParentClass(parent, (Class<?>)child); + return false; + } + + /** * Comparator for use with {@link TreeMap TreeMaps} with {@link Class} keys. */ public final static class ClassComparator implements Comparator<Class<?>>, Serializable { http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/d6fe4ff9/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java b/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java index df39005..afc7a1e 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java @@ -14,8 +14,6 @@ package org.apache.juneau.rest; import static javax.servlet.http.HttpServletResponse.*; import static org.apache.juneau.dto.swagger.SwaggerBuilder.*; -import static org.apache.juneau.internal.ClassUtils.*; -import static org.apache.juneau.rest.CallMethod.ParamType.*; import static org.apache.juneau.rest.RestContext.*; import static org.apache.juneau.rest.annotation.Inherit.*; import static org.apache.juneau.serializer.SerializerContext.*; @@ -32,7 +30,6 @@ import org.apache.juneau.*; import org.apache.juneau.dto.swagger.*; import org.apache.juneau.encoders.*; import org.apache.juneau.html.*; -import org.apache.juneau.http.*; import org.apache.juneau.internal.*; import org.apache.juneau.json.*; import org.apache.juneau.parser.*; @@ -310,104 +307,76 @@ class CallMethod implements Comparable<CallMethod> { */ private static class MethodParam { - private final ParamType paramType; - private final Type type; - private final String name; - private final boolean multiPart, plainParams; private final int attrIdx; + private final RestParam param; private MethodParam(Type type, Method method, Annotation[] annotations, boolean methodPlainParams, UrlPathPattern pathPattern, int attrIdx) throws ServletException { - this.type = type; - ParamType _paramType = null; + RestParam _param = null; String _name = ""; - boolean _multiPart = false, _plainParams = false; boolean isClass = type instanceof Class; - if (isClass && isParentClass(HttpServletRequest.class, (Class<?>)type)) - _paramType = REQ; - else if (isClass && isParentClass(HttpServletResponse.class, (Class<?>)type)) - _paramType = RES; - else if (isClass && isParentClass(Accept.class, (Class<?>)type)) - _paramType = ACCEPT; - else if (isClass && isParentClass(AcceptEncoding.class, (Class<?>)type)) - _paramType = ACCEPTENCODING; - else if (isClass && isParentClass(ContentType.class, (Class<?>)type)) - _paramType = CONTENTTYPE; - else for (Annotation a : annotations) { - if (a instanceof Path) { - Path a2 = (Path)a; - _paramType = PATH; - _name = a2.value(); - } else if (a instanceof Header) { - Header h = (Header)a; - _paramType = HEADER; - _name = h.value(); - } else if (a instanceof FormData) { - FormData p = (FormData)a; - if (p.multipart()) - assertCollection(type, method); - _paramType = FORMDATA; - _multiPart = p.multipart(); - _plainParams = p.format().equals("INHERIT") ? methodPlainParams : p.format().equals("PLAIN"); - _name = p.value(); - } else if (a instanceof Query) { - Query p = (Query)a; - if (p.multipart()) - assertCollection(type, method); - _paramType = QUERY; - _multiPart = p.multipart(); - _plainParams = p.format().equals("INHERIT") ? methodPlainParams : p.format().equals("PLAIN"); - _name = p.value(); - } else if (a instanceof HasFormData) { - HasFormData p = (HasFormData)a; - _paramType = HASFORMDATA; - _name = p.value(); - } else if (a instanceof HasQuery) { - HasQuery p = (HasQuery)a; - _paramType = HASQUERY; - _name = p.value(); - } else if (a instanceof Body) { - _paramType = BODY; - } else if (a instanceof org.apache.juneau.rest.annotation.Method) { - _paramType = METHOD; - if (type != String.class) - throw new ServletException("@Method parameters must be of type String"); - } else if (a instanceof PathRemainder) { - _paramType = PATHREMAINDER; - if (type != String.class) - throw new ServletException("@PathRemainder parameters must be of type String"); - } else if (a instanceof Properties) { - _paramType = PROPS; - _name = "PROPERTIES"; - } else if (a instanceof Messages) { - _paramType = MESSAGES; - _name = "MESSAGES"; + if (isClass) + _param = RestParam.STANDARD_RESOLVERS.get(type); + + if (_param == null) { + for (Annotation a : annotations) { + if (a instanceof Path) { + Path a2 = (Path)a; + _name = a2.value(); + } else if (a instanceof Header) { + _param = new RestParam.HeaderObject(((Header)a).value(), type); + } else if (a instanceof FormData) { + FormData p = (FormData)a; + if (p.multipart()) + assertCollection(type, method); + boolean plainParams = p.format().equals("INHERIT") ? methodPlainParams : p.format().equals("PLAIN"); + _param = new RestParam.FormDataObject(p.value(), type, p.multipart(), plainParams); + } else if (a instanceof Query) { + Query p = (Query)a; + if (p.multipart()) + assertCollection(type, method); + boolean plainParams = p.format().equals("INHERIT") ? methodPlainParams : p.format().equals("PLAIN"); + _param = new RestParam.QueryObject(p.value(), type, p.multipart(), plainParams); + } else if (a instanceof HasFormData) { + _param = new RestParam.HasFormDataObject(((HasFormData)a).value(), type); + } else if (a instanceof HasQuery) { + _param = new RestParam.HasQueryObject(((HasQuery)a).value(), type); + } else if (a instanceof Body) { + _param = new RestParam.BodyObject(type); + } else if (a instanceof org.apache.juneau.rest.annotation.Method) { + _param = new RestParam.MethodObject(type); + } else if (a instanceof PathRemainder) { + _param = new RestParam.PathRemainderObject(type); + } else if (a instanceof Properties) { + _param = new RestParam.PropsObject(type); + } else if (a instanceof Messages) { + _param = new RestParam.MessageBundleObject(); + } } } - if (_paramType == null) - _paramType = PATH; - - if (_paramType == PATH && _name.isEmpty()) { - int idx = attrIdx++; - String[] vars = pathPattern.getVars(); - if (vars.length <= idx) - throw new RestServletException("Number of attribute parameters in method ''{0}'' exceeds the number of URL pattern variables.", method.getName()); - - // Check for {#} variables. - String idxs = String.valueOf(idx); - for (int i = 0; i < vars.length; i++) - if (StringUtils.isNumeric(vars[i]) && vars[i].equals(idxs)) - _name = vars[i]; - - if (_name.isEmpty()) - _name = pathPattern.getVars()[idx]; + + if (_param == null) { + + if (_name.isEmpty()) { + int idx = attrIdx++; + String[] vars = pathPattern.getVars(); + if (vars.length <= idx) + throw new RestServletException("Number of attribute parameters in method ''{0}'' exceeds the number of URL pattern variables.", method.getName()); + + // Check for {#} variables. + String idxs = String.valueOf(idx); + for (int i = 0; i < vars.length; i++) + if (StringUtils.isNumeric(vars[i]) && vars[i].equals(idxs)) + _name = vars[i]; + + if (_name.isEmpty()) + _name = pathPattern.getVars()[idx]; + } + _param = new RestParam.PathParameterObject(_name, type); } - this.paramType = _paramType; - this.name = _name; - this.multiPart = _multiPart; - this.plainParams = _plainParams; + this.param = _param; this.attrIdx = attrIdx; } @@ -421,56 +390,19 @@ class CallMethod implements Comparable<CallMethod> { } private Object getValue(RestRequest req, RestResponse res) throws Exception { - BeanSession session = req.getBeanSession(); - switch(paramType) { - case REQ: return req; - case RES: return res; - case PATH: return req.getPathParams().get(name, type); - case BODY: return req.getBody().asType(type); - case HEADER: return req.getHeaders().get(name, type); - case METHOD: return req.getMethod(); - case FORMDATA: { - if (multiPart) - return req.getFormData().getAll(name, type); - if (plainParams) - return session.convertToType(req.getFormData(name), session.getClassMeta(type)); - return req.getFormData().get(name, type); - } - case QUERY: { - if (multiPart) - return req.getQuery().getAll(name, type); - if (plainParams) - return session.convertToType(req.getQuery(name), session.getClassMeta(type)); - return req.getQuery().get(name, type); - } - case HASFORMDATA: return session.convertToType(req.getFormData().containsKey(name), session.getClassMeta(type)); - case HASQUERY: return session.convertToType(req.getQuery().containsKey(name), session.getClassMeta(type)); - case PATHREMAINDER: return req.getPathRemainder(); - case PROPS: return res.getProperties(); - case MESSAGES: return req.getResourceBundle(); - case ACCEPT: return req.getHeaders().getAccept(); - case ACCEPTENCODING:return req.getHeaders().getAcceptEncoding(); - case CONTENTTYPE: return req.getHeaders().getContentType(); - default: return null; - } + return param.resolve(req, res); } - } - static enum ParamType { - REQ, RES, PATH, BODY, HEADER, METHOD, FORMDATA, QUERY, HASFORMDATA, HASQUERY, PATHREMAINDER, PROPS, MESSAGES, ACCEPT, ACCEPTENCODING, CONTENTTYPE; - - private String getSwaggerParameterType() { - switch(this) { - case PATH: return "path"; - case HEADER: - case ACCEPT: - case ACCEPTENCODING: - case CONTENTTYPE: return "header"; - case FORMDATA: return "formData"; - case QUERY: return "query"; - case BODY: return "body"; - default: return null; - } + private RestParamType getParamType() { + return param.getParamType(); + } + + private String getName() { + return param.getName(); + } + + private Type getType() { + return param.getType(); } } @@ -702,12 +634,12 @@ class CallMethod implements Comparable<CallMethod> { // Finally, look for parameters defined on method. for (CallMethod.MethodParam mp : this.params) { - String in = mp.paramType.getSwaggerParameterType(); - if (in != null) { - String k2 = in + '.' + ("body".equals(in) ? null : mp.name); + RestParamType in = mp.getParamType(); + if (in != RestParamType.OTHER) { + String k2 = in.toString() + '.' + (in == RestParamType.BODY ? null : mp.getName()); ParameterInfo p = m.get(k2); if (p == null) { - p = parameterInfoStrict(in, mp.name); + p = parameterInfoStrict(in.toString(), mp.getName()); m.put(k2, p); } } @@ -874,7 +806,7 @@ class CallMethod implements Comparable<CallMethod> { } catch (Exception e) { throw new RestException(SC_BAD_REQUEST, "Invalid data conversion. Could not convert {0} ''{1}'' to type ''{2}'' on method ''{3}.{4}''.", - params[i].paramType.name(), params[i].name, params[i].type, method.getDeclaringClass().getName(), method.getName() + params[i].getParamType().name(), params[i].getName(), params[i].getType(), method.getDeclaringClass().getName(), method.getName() ).initCause(e); } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/d6fe4ff9/juneau-rest/src/main/java/org/apache/juneau/rest/RestParam.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestParam.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestParam.java index a900c14..c6e176e 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestParam.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestParam.java @@ -174,6 +174,14 @@ public abstract class RestParam { return name; } + /** + * Returns the parameter class type. + * @return the parameter class type. + */ + public Type getType() { + return type; + } + //------------------------------------------------------------------------------------------------------------------- // Request / Response retrievers //------------------------------------------------------------------------------------------------------------------- @@ -233,7 +241,7 @@ public abstract class RestParam { static final class AcceptHeader extends RestParam { protected AcceptHeader() { - super(HEADER, "Accept-Header", AcceptHeader.class); + super(HEADER, "Accept-Header", Accept.class); } @Override /* RestParam */ @@ -620,8 +628,10 @@ public abstract class RestParam { static final class MethodObject extends RestParam { - protected MethodObject() { + protected MethodObject(Type type) throws ServletException { super(OTHER, null, null); + if (type != String.class) + throw new ServletException("@Method parameters must be of type String"); } @Override /* RestParam */ @@ -698,8 +708,10 @@ public abstract class RestParam { static final class PathRemainderObject extends RestParam { - protected PathRemainderObject() { + protected PathRemainderObject(Type type) throws ServletException { super(OTHER, null, null); + if (type != String.class) + throw new ServletException("@PathRemainder parameters must be of type String"); } @Override /* RestParam */ @@ -710,8 +722,10 @@ public abstract class RestParam { static final class PropsObject extends RestParam { - protected PropsObject() { + protected PropsObject(Type type) throws ServletException { super(OTHER, null, null); + if (! ClassUtils.isParentClass(LinkedHashMap.class, type)) + throw new ServletException("@PathRemainder parameters must be of type String"); } @Override /* RestParam */
