| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.wink.common.model.wadl; |
| |
| import java.lang.annotation.Annotation; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.ws.rs.DefaultValue; |
| import javax.ws.rs.FormParam; |
| import javax.ws.rs.HeaderParam; |
| import javax.ws.rs.MatrixParam; |
| import javax.ws.rs.Path; |
| import javax.ws.rs.PathParam; |
| import javax.ws.rs.QueryParam; |
| import javax.ws.rs.core.MediaType; |
| import javax.xml.namespace.QName; |
| |
| import org.apache.wink.common.DynamicResource; |
| import org.apache.wink.common.internal.registry.Injectable; |
| import org.apache.wink.common.internal.registry.Injectable.ParamType; |
| import org.apache.wink.common.internal.registry.metadata.ClassMetadata; |
| import org.apache.wink.common.internal.registry.metadata.MethodMetadata; |
| import org.apache.wink.common.internal.registry.metadata.ResourceMetadataCollector; |
| import org.apache.wink.common.internal.uritemplate.JaxRsUriTemplateProcessor; |
| import org.apache.wink.common.internal.uritemplate.UriTemplateProcessor; |
| |
| /** |
| * @Path("/sfdsf"); public class MyResource { |
| * @Context javax.ws.rs.core.Application app; |
| * @OPTIONS public org.apache.wink.common.model.wadl.Application getWADL() { |
| * return new WADLGenerator().generate(app.getClasses()); } } |
| */ |
| public class WADLGenerator { |
| |
| private static final String XML_SCHEMA_NS = "http://www.w3.org/2001/XMLSchema"; |
| |
| public Application generate(String baseURI, Set<Class<?>> classes) { |
| /* |
| * the idea is that classes comes from the Application subclass |
| */ |
| Application app = new Application(); |
| if (classes == null || classes.isEmpty()) { |
| return app; |
| } |
| |
| Resources resources = new Resources(); |
| resources.setBase(baseURI); |
| |
| Set<ClassMetadata> metadataSet = buildClassMetdata(classes); |
| resources.getResource().addAll(buildResources(metadataSet)); |
| app.getResources().add(resources); |
| return app; |
| } |
| |
| /* package */Set<ClassMetadata> buildClassMetdata(Set<Class<?>> classes) { |
| Set<ClassMetadata> metadataSet = new HashSet<ClassMetadata>(classes.size()); |
| for (Class<?> c : classes) { |
| if (!isResource(c)) { |
| /* not a resource, so skip it */ |
| continue; |
| } |
| |
| ClassMetadata metadata = ResourceMetadataCollector.collectMetadata(c); |
| metadataSet.add(metadata); |
| } |
| |
| return metadataSet; |
| } |
| |
| /* package */Set<Resource> buildResources(Set<ClassMetadata> metadataSet) { |
| Set<Resource> s = new HashSet<Resource>(metadataSet.size()); |
| for (ClassMetadata metadata : metadataSet) { |
| Resource r = buildResource(metadata); |
| s.add(r); |
| } |
| |
| return s; |
| } |
| |
| /* package */Resource buildResource(ClassMetadata metadata) { |
| Resource r = new Resource(); |
| |
| if (metadata != null) { |
| Class<?> resClass = metadata.getResourceClass(); |
| if (resClass != null) { |
| WADLDoc d = resClass.getAnnotation(WADLDoc.class); |
| if (d != null) { |
| r.getDoc().add(getDocument(d)); |
| } |
| } |
| } |
| |
| /* set the path */ |
| String path = metadata.getPath(); |
| |
| if (path == null) { |
| Class<?> resClass = metadata.getResourceClass(); |
| if (DynamicResource.class.isAssignableFrom(resClass)) { |
| try { |
| DynamicResource dynRes = (DynamicResource)resClass.newInstance(); |
| path = dynRes.getPath(); |
| } catch (Exception e) { |
| // Drop through and look for @Path annotation. |
| } |
| } |
| } |
| |
| UriTemplateProcessor processor = JaxRsUriTemplateProcessor.newNormalizedInstance(path); |
| String pathStr = processor.getTemplate(); |
| for (String var : processor.getVariableNames()) { |
| pathStr = pathStr.replaceAll("\\{(\\s)*" + var + "(\\s)*:.*\\}", "{" + var + "}"); |
| } |
| r.setPath(pathStr); |
| |
| List<Object> methodOrSubresource = r.getMethodOrResource(); |
| List<Param> resourceParams = r.getParam(); |
| |
| List<MethodMetadata> methodMetadata = metadata.getResourceMethods(); |
| |
| if (methodMetadata != null && !methodMetadata.isEmpty()) { |
| for (MethodMetadata methodMeta : methodMetadata) { |
| Method m = buildMethod(metadata, methodMeta); |
| methodOrSubresource.add(m); |
| |
| /* also scan for all the path and matrix parameters */ |
| List<Injectable> params = methodMeta.getFormalParameters(); |
| if (params != null && params.size() > 0) { |
| for (Injectable p : params) { |
| Param param = null; |
| boolean isUnique = true; |
| switch (p.getParamType()) { |
| case QUERY: |
| /* do nothing */ |
| break; |
| case HEADER: |
| /* do nothing */ |
| break; |
| case ENTITY: |
| /* do nothing */ |
| break; |
| case COOKIE: |
| /* not supported in WADL */ |
| break; |
| case FORM: |
| /* should show up in the representation instead */ |
| break; |
| case PATH: |
| param = buildParam(p); |
| for (Param rParam : resourceParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| resourceParams.add(param); |
| } |
| break; |
| case MATRIX: |
| param = buildParam(p); |
| for (Param rParam : resourceParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| resourceParams.add(param); |
| } |
| break; |
| case CONTEXT: |
| /* do nothing */ |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * list the class level parameters |
| */ |
| List<Injectable> fields = metadata.getInjectableFields(); |
| if (fields != null) { |
| for (Injectable p : metadata.getInjectableFields()) { |
| Param param = null; |
| boolean isUnique = true; |
| |
| switch (p.getParamType()) { |
| case QUERY: |
| resourceParams.add(buildParam(p)); |
| break; |
| case HEADER: |
| resourceParams.add(buildParam(p)); |
| break; |
| case ENTITY: |
| /* do nothing */ |
| break; |
| case COOKIE: |
| /* not supported in WADL */ |
| break; |
| case FORM: |
| /* should show up in the representation instead */ |
| break; |
| case PATH: |
| param = buildParam(p); |
| for (Param rParam : resourceParams) { |
| if (param.getName() != null && param.getName().equals(rParam.getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| resourceParams.add(param); |
| } |
| break; |
| case MATRIX: |
| param = buildParam(p); |
| for (Param rParam : resourceParams) { |
| if (param.getName() != null && param.getName().equals(rParam.getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| resourceParams.add(param); |
| } |
| break; |
| case CONTEXT: |
| /* do nothing */ |
| break; |
| } |
| } |
| } |
| |
| /* |
| * list subresource methods |
| */ |
| methodMetadata = metadata.getSubResourceMethods(); |
| if (methodMetadata != null && !methodMetadata.isEmpty()) { |
| for (MethodMetadata methodMeta : methodMetadata) { |
| Resource subRes = new Resource(); |
| Method m = buildMethod(metadata, methodMeta); |
| subRes.getMethodOrResource().add(m); |
| subRes.setPath(methodMeta.getPath()); |
| methodOrSubresource.add(subRes); |
| List<Param> subResParams = subRes.getParam(); |
| /* also scan for all the path and matrix parameters */ |
| List<Injectable> params = methodMeta.getFormalParameters(); |
| if (params != null && params.size() > 0) { |
| for (Injectable p : params) { |
| Param param = null; |
| boolean isUnique = true; |
| |
| switch (p.getParamType()) { |
| case QUERY: |
| /* do nothing */ |
| break; |
| case HEADER: |
| /* do nothing */ |
| break; |
| case ENTITY: |
| /* do nothing */ |
| break; |
| case COOKIE: |
| /* not supported in WADL */ |
| break; |
| case FORM: |
| /* should show up in the representation instead */ |
| break; |
| case PATH: |
| param = buildParam(p); |
| for (Param rParam : subResParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| subRes.getParam().add(param); |
| } |
| break; |
| case MATRIX: |
| param = buildParam(p); |
| for (Param rParam : subResParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| subRes.getParam().add(param); |
| } |
| break; |
| case CONTEXT: |
| /* do nothing */ |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * list subresource locators |
| */ |
| methodMetadata = metadata.getSubResourceLocators(); |
| if (methodMetadata != null && !methodMetadata.isEmpty()) { |
| for (MethodMetadata methodMeta : methodMetadata) { |
| Resource subRes = new Resource(); |
| subRes.setPath(methodMeta.getPath()); |
| |
| if (methodMeta != null) { |
| java.lang.reflect.Method reflMethod = methodMeta.getReflectionMethod(); |
| if (reflMethod != null) { |
| WADLDoc d = reflMethod.getAnnotation(WADLDoc.class); |
| if (d != null) { |
| subRes.getDoc().add(getDocument(d)); |
| } |
| } |
| } |
| |
| methodOrSubresource.add(subRes); |
| |
| /* also scan for all the path and matrix parameters */ |
| List<Injectable> params = methodMeta.getFormalParameters(); |
| List<Param> subResParams = subRes.getParam(); |
| if (params != null && params.size() > 0) { |
| for (Injectable p : params) { |
| Param param = null; |
| boolean isUnique = true; |
| |
| switch (p.getParamType()) { |
| case QUERY: |
| param = buildParam(p); |
| for (Param rParam : subResParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| subRes.getParam().add(param); |
| } |
| break; |
| case HEADER: |
| param = buildParam(p); |
| for (Param rParam : subResParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| subRes.getParam().add(param); |
| } |
| break; |
| case ENTITY: |
| /* do nothing */ |
| break; |
| case COOKIE: |
| /* not supported in WADL */ |
| break; |
| case FORM: |
| /* should show up in the representation instead */ |
| break; |
| case PATH: |
| param = buildParam(p); |
| for (Param rParam : subResParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| subRes.getParam().add(param); |
| } |
| break; |
| case MATRIX: |
| param = buildParam(p); |
| for (Param rParam : subResParams) { |
| if (param.getName() != null && param.getName().equals(rParam |
| .getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| subRes.getParam().add(param); |
| } |
| break; |
| case CONTEXT: |
| /* do nothing */ |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| return r; |
| } |
| |
| /* package */Method buildMethod(ClassMetadata classMetadata, MethodMetadata metadata) { |
| Method m = new Method(); |
| m.setName(metadata.getHttpMethod()); |
| |
| java.lang.reflect.Method reflMethod = metadata.getReflectionMethod(); |
| if (reflMethod != null) { |
| WADLDoc d = reflMethod.getAnnotation(WADLDoc.class); |
| if (d != null) { |
| m.getDoc().add(getDocument(d)); |
| } |
| } |
| |
| Request r = buildRequest(classMetadata, metadata); |
| if (r != null) { |
| m.setRequest(r); |
| } |
| |
| List<Response> resp = buildResponse(metadata); |
| if (resp != null) { |
| m.getResponse().addAll(resp); |
| } |
| return m; |
| } |
| |
| /* package */Request buildRequest(ClassMetadata classMetadata, MethodMetadata metadata) { |
| Request r = null; |
| |
| List<Injectable> params = metadata.getFormalParameters(); |
| if (params != null && params.size() > 0) { |
| if (r == null) { |
| r = new Request(); |
| } |
| boolean hasValidParams = false; |
| List<Param> requestParams = r.getParam(); |
| for (Injectable p : params) { |
| Param param = null; |
| boolean isUnique = true; |
| switch (p.getParamType()) { |
| case QUERY: |
| hasValidParams = true; |
| param = buildParam(p); |
| for (Param rParam : requestParams) { |
| if (param.getName() != null && param.getName().equals(rParam.getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| requestParams.add(buildParam(p)); |
| } |
| |
| break; |
| case HEADER: |
| hasValidParams = true; |
| param = buildParam(p); |
| for (Param rParam : requestParams) { |
| if (param.getName() != null && param.getName().equals(rParam.getName()) |
| && rParam.getStyle().equals(param.getStyle())) { |
| isUnique = false; |
| } |
| } |
| if (isUnique) { |
| requestParams.add(buildParam(p)); |
| } |
| break; |
| case ENTITY: |
| hasValidParams = true; |
| |
| Annotation[] anns = p.getAnnotations(); |
| if (anns != null && anns.length > 0) { |
| for (Annotation a : anns) { |
| if (WADLDoc.class.equals(a.annotationType())) { |
| WADLDoc d = (WADLDoc)a; |
| r.getDoc().add(getDocument(d)); |
| } |
| } |
| } |
| |
| /* need to build the representation */ |
| Set<Representation> representations = |
| buildIncomingRepresentation(classMetadata, metadata, p); |
| if (representations != null) |
| r.getRepresentation().addAll(representations); |
| break; |
| case COOKIE: |
| /* not supported in WADL */ |
| break; |
| case FORM: |
| /* should show up in the representation instead */ |
| break; |
| case PATH: |
| /* should show up in the containing resource */ |
| break; |
| case MATRIX: |
| /* should show up in the containing resource */ |
| break; |
| case CONTEXT: |
| /* do nothing */ |
| break; |
| } |
| } |
| if (!hasValidParams) { |
| r = null; |
| } |
| } |
| |
| return r; |
| } |
| |
| /* package */Param buildParam(Injectable paramMetadata) { |
| Param p = null; |
| ParamType pt = paramMetadata.getParamType(); |
| Annotation[] annotations = paramMetadata.getAnnotations(); |
| switch (pt) { |
| case HEADER: |
| p = new Param(); |
| p.setStyle(ParamStyle.HEADER); |
| if (annotations != null) { |
| for (Annotation a : annotations) { |
| if (HeaderParam.class.equals(a.annotationType())) { |
| HeaderParam paramAnn = (HeaderParam)a; |
| p.setName(paramAnn.value()); |
| } |
| } |
| } |
| break; |
| case MATRIX: |
| p = new Param(); |
| p.setStyle(ParamStyle.MATRIX); |
| for (Annotation a : annotations) { |
| if (MatrixParam.class.equals(a.annotationType())) { |
| MatrixParam paramAnn = (MatrixParam)a; |
| p.setName(paramAnn.value()); |
| } |
| } |
| break; |
| case PATH: |
| p = new Param(); |
| p.setStyle(ParamStyle.TEMPLATE); |
| for (Annotation a : annotations) { |
| if (PathParam.class.equals(a.annotationType())) { |
| PathParam paramAnn = (PathParam)a; |
| p.setName(paramAnn.value()); |
| } |
| } |
| break; |
| case QUERY: |
| p = new Param(); |
| p.setStyle(ParamStyle.QUERY); |
| for (Annotation a : annotations) { |
| if (QueryParam.class.equals(a.annotationType())) { |
| QueryParam paramAnn = (QueryParam)a; |
| p.setName(paramAnn.value()); |
| } |
| } |
| break; |
| case FORM: |
| p = new Param(); |
| p.setStyle(ParamStyle.QUERY); |
| for (Annotation a : annotations) { |
| if (FormParam.class.equals(a.annotationType())) { |
| FormParam paramAnn = (FormParam)a; |
| p.setName(paramAnn.value()); |
| } |
| } |
| break; |
| case CONTEXT: |
| break; |
| case COOKIE: |
| break; |
| case ENTITY: |
| break; |
| } |
| |
| if (p == null) { |
| /* |
| * The paramtype was never set so return null. This might have been |
| * some other type of injectable that shouldn't be created as a |
| * Param. This is a preventive measure. |
| */ |
| return null; |
| } |
| |
| Class<?> memberType = paramMetadata.getType(); |
| if (memberType.equals(int.class) || memberType.equals(Integer.class)) { |
| p.setType(new QName(XML_SCHEMA_NS, "int")); |
| } else if (memberType.equals(float.class) || memberType.equals(Float.class)) { |
| p.setType(new QName(XML_SCHEMA_NS, "float")); |
| } else if (memberType.equals(long.class) || memberType.equals(Long.class)) { |
| p.setType(new QName(XML_SCHEMA_NS, "long")); |
| } else if (memberType.equals(boolean.class) || memberType.equals(Boolean.class)) { |
| p.setType(new QName(XML_SCHEMA_NS, "boolean")); |
| } else if (memberType.equals(short.class) || memberType.equals(Short.class)) { |
| p.setType(new QName(XML_SCHEMA_NS, "short")); |
| } else if (memberType.equals(double.class) || memberType.equals(Double.class)) { |
| p.setType(new QName(XML_SCHEMA_NS, "double")); |
| } else if (memberType.equals(byte.class) || memberType.equals(Byte.class)) { |
| p.setType(new QName(XML_SCHEMA_NS, "byte")); |
| } |
| |
| for (Annotation a : annotations) { |
| if (DefaultValue.class.equals(a.annotationType())) { |
| DefaultValue paramAnn = (DefaultValue)a; |
| p.setDefault(paramAnn.value()); |
| } |
| |
| if (WADLDoc.class.equals(a.annotationType())) { |
| WADLDoc d = (WADLDoc)a; |
| p.getDoc().add(getDocument(d)); |
| } |
| } |
| |
| return p; |
| } |
| |
| /* package */Set<Representation> buildIncomingRepresentation(ClassMetadata classMetadata, |
| MethodMetadata methodMetadata, |
| Injectable metadata) { |
| if (methodMetadata == null) { |
| return null; |
| } |
| |
| if (metadata != null && metadata.getParamType() != ParamType.ENTITY) { |
| throw new IllegalArgumentException("Parameter data is not for an entity."); |
| } |
| |
| /* |
| * first check all the consumes |
| */ |
| Set<MediaType> consumesMT = methodMetadata.getConsumes(); |
| Set<Representation> reps = null; |
| if (consumesMT != null && !consumesMT.isEmpty()) { |
| reps = new HashSet<Representation>(); |
| for (MediaType mt : consumesMT) { |
| Representation r = new Representation(); |
| r.setMediaType(mt.toString()); |
| |
| /* |
| * if the representation is a special case, we need to build for |
| * it |
| */ |
| /* |
| * special cases include application/xml, text/xml; should set |
| * the element attribute |
| */ |
| List<Param> params = new ArrayList<Param>(); |
| if (mt.isCompatible(MediaType.APPLICATION_FORM_URLENCODED_TYPE) || mt |
| .isCompatible(MediaType.MULTIPART_FORM_DATA_TYPE)) { |
| List<Injectable> injectables = methodMetadata.getFormalParameters(); |
| if (injectables != null) { |
| for (Injectable i : injectables) { |
| if (ParamType.FORM.equals(i.getParamType())) { |
| params.add(buildParam(i)); |
| } |
| } |
| } |
| |
| /* |
| * should we scan the class metadata too? FormParams aren't |
| * required to be supported in other places than the |
| * resource method parameters |
| */ |
| if (!params.isEmpty()) { |
| r.getParam().addAll(params); |
| } |
| } |
| reps.add(r); |
| } |
| } else { |
| if (metadata == null) { |
| return null; |
| } |
| |
| /* |
| * there aren't any consumes so we can't look for that but maybe we |
| * can look at the Providers registry and find all the relevant |
| * media types there |
| */ |
| } |
| |
| return reps; |
| } |
| |
| /* package */List<Response> buildResponse(MethodMetadata metadata) { |
| if (metadata == null) { |
| return null; |
| } |
| Response r = null; |
| // Set<MediaType> produces = metadata.getProduces(); |
| Set<Representation> representations = buildOutgoingRepresentation(metadata, null); |
| if (representations != null && !representations.isEmpty()) { |
| r = new Response(); |
| r.getRepresentation().addAll(representations); |
| } |
| |
| java.lang.reflect.Method m = metadata.getReflectionMethod(); |
| if (Void.TYPE.equals(m.getReturnType())) { |
| if (r == null) { |
| r = new Response(); |
| } |
| r.getStatus().add(Long.valueOf(204)); |
| } else if (!javax.ws.rs.core.Response.class.isAssignableFrom(m.getReturnType())) { |
| if (r == null) { |
| r = new Response(); |
| } |
| r.getStatus().add(Long.valueOf(200)); |
| } |
| |
| return Collections.singletonList(r); |
| } |
| |
| /* package */Set<Representation> buildOutgoingRepresentation(MethodMetadata methodMetadata, |
| Class<?> returnType) { |
| if (methodMetadata == null) { |
| return null; |
| } |
| |
| /* |
| * first check all the consumes |
| */ |
| Set<MediaType> producesMT = methodMetadata.getProduces(); |
| Set<Representation> reps = null; |
| if (producesMT != null && !producesMT.isEmpty()) { |
| reps = new HashSet<Representation>(); |
| for (MediaType mt : producesMT) { |
| Representation r = new Representation(); |
| r.setMediaType(mt.toString()); |
| |
| /* |
| * if the representation is a special case, we need to build for |
| * it |
| */ |
| /* |
| * TODO: special cases include application/xml, text/xml; should |
| * set the element attribute |
| */ |
| reps.add(r); |
| } |
| } else { |
| /* |
| * there aren't any produces so we can't look for that but maybe we |
| * can look at the Providers registry and find all the relevant |
| * media types there |
| */ |
| } |
| |
| return reps; |
| } |
| |
| /* package */Doc getDocument(WADLDoc desc) { |
| Doc d = new Doc(); |
| d.setTitle(desc.value()); |
| if (!"".equals(desc.content())) { |
| d.getContent().add(desc.content()); |
| } |
| return d; |
| } |
| |
| /* |
| * Customized isResource method so it accepts interfaces. |
| */ |
| protected boolean isResource(Class<?> cls) { |
| if (ResourceMetadataCollector.isDynamicResource(cls)) { |
| return true; |
| } |
| |
| if (cls.getAnnotation(Path.class) != null) { |
| return true; |
| } |
| |
| Class<?> declaringClass = cls; |
| |
| while (!declaringClass.equals(Object.class)) { |
| // try a superclass |
| Class<?> superclass = declaringClass.getSuperclass(); |
| if (superclass.getAnnotation(Path.class) != null) { |
| return true; |
| } |
| |
| // try interfaces |
| Class<?>[] interfaces = declaringClass.getInterfaces(); |
| for (Class<?> interfaceClass : interfaces) { |
| if (interfaceClass.getAnnotation(Path.class) != null) { |
| return true; |
| } |
| } |
| declaringClass = declaringClass.getSuperclass(); |
| } |
| return false; |
| } |
| |
| } |