Return-Path: X-Original-To: apmail-geronimo-xbean-scm-archive@minotaur.apache.org Delivered-To: apmail-geronimo-xbean-scm-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0E72BD404 for ; Fri, 25 Jan 2013 19:38:47 +0000 (UTC) Received: (qmail 82294 invoked by uid 500); 25 Jan 2013 19:38:47 -0000 Delivered-To: apmail-geronimo-xbean-scm-archive@geronimo.apache.org Received: (qmail 82266 invoked by uid 500); 25 Jan 2013 19:38:46 -0000 Mailing-List: contact xbean-scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: xbean-scm@geronimo.apache.org Delivered-To: mailing list xbean-scm@geronimo.apache.org Received: (qmail 82255 invoked by uid 99); 25 Jan 2013 19:38:46 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 25 Jan 2013 19:38:46 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 25 Jan 2013 19:38:41 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 329C323888E7; Fri, 25 Jan 2013 19:38:21 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1438661 - in /geronimo/xbean/trunk/xbean-finder/src: main/java/org/apache/xbean/finder/AnnotationFinder.java main/java/org/apache/xbean/finder/Parameter.java test/java/org/apache/xbean/finder/AnnotatedParametersTest.java Date: Fri, 25 Jan 2013 19:38:21 -0000 To: xbean-scm@geronimo.apache.org From: dblevins@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130125193821.329C323888E7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dblevins Date: Fri Jan 25 19:38:20 2013 New Revision: 1438661 URL: http://svn.apache.org/viewvc?rev=1438661&view=rev Log: Excellent patch from Matt Benson. Thank you, Matt! XBEAN-237: AnnotationFinder should provide methods to search for annotated method/constructor parameters Added: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/Parameter.java (with props) geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/AnnotatedParametersTest.java (with props) Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java?rev=1438661&r1=1438660&r2=1438661&view=diff ============================================================================== --- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java (original) +++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AnnotationFinder.java Fri Jan 25 19:38:20 2013 @@ -149,7 +149,13 @@ public class AnnotationFinder implements classInfos.put(info.name, info); index(info); index(info.constructors); + for (MethodInfo ctor : info.constructors) { + index(ctor.parameters); + } index(info.methods); + for (MethodInfo method : info.methods) { + index(method.parameters); + } index(info.fields); } @@ -636,6 +642,52 @@ public class AnnotationFinder implements return methods; } + public List> findAnnotatedMethodParameters(Class annotation) { + classesNotLoaded.clear(); + + final Set seen = checkRuntimeAnnotation ? new HashSet() : null; + final List> result = new ArrayList>(); + for (Info info : getAnnotationInfos(annotation.getName())) { + if (!(info instanceof ParameterInfo)) { + continue; + } + final ParameterInfo parameterInfo = (ParameterInfo) info; + if ("".equals(parameterInfo.getDeclaringMethod().getName())) { + continue; + } + final ClassInfo classInfo = parameterInfo.getDeclaringMethod().getDeclaringClass(); + + if (checkRuntimeAnnotation) { + if (!seen.add(classInfo)) { + continue; + } + try { + Class clazz = classInfo.get(); + for (Method method : clazz.getDeclaredMethods()) { + for (Annotation[] annotations : method.getParameterAnnotations()) { + for (int i = 0; i < annotations.length; i++) { + if (annotations[i].annotationType().equals(annotation)) { + result.add(Parameter.declaredBy(method, i)); + } + } + } + } + } catch (ClassNotFoundException e) { + classesNotLoaded.add(classInfo.getName()); + } + } else { + try { + @SuppressWarnings("unchecked") + final Parameter parameter = (Parameter) parameterInfo.get(); + result.add(parameter); + } catch (ClassNotFoundException e) { + classesNotLoaded.add(parameterInfo.getDeclaringMethod().getDeclaringClass().getName()); + } + } + } + return result; + } + public List> findMetaAnnotatedMethods(Class annotation) { classesNotLoaded.clear(); @@ -792,6 +844,54 @@ public class AnnotationFinder implements return constructors; } + public List>> findAnnotatedConstructorParameters(Class annotation) { + classesNotLoaded.clear(); + + final Set seen = checkRuntimeAnnotation ? new HashSet() : null; + final List>> result = new ArrayList>>(); + for (Info info : getAnnotationInfos(annotation.getName())) { + if (!(info instanceof ParameterInfo)) { + continue; + } + final ParameterInfo parameterInfo = (ParameterInfo) info; + if (!"".equals(parameterInfo.getDeclaringMethod().getName())) { + continue; + } + final ClassInfo classInfo = parameterInfo.getDeclaringMethod().getDeclaringClass(); + + if (checkRuntimeAnnotation) { + if (!seen.add(classInfo)) { + continue; + } + try { + Class clazz = classInfo.get(); + for (Constructor ctor : clazz.getDeclaredConstructors()) { + for (Annotation[] annotations : ctor.getParameterAnnotations()) { + for (int i = 0; i < annotations.length; i++) { + if (annotations[i].annotationType().equals(annotation)) { + @SuppressWarnings({ "rawtypes", "unchecked" }) + final Parameter> parameter = Parameter.declaredBy((Constructor) ctor, i); + result.add(parameter); + } + } + } + } + } catch (ClassNotFoundException e) { + classesNotLoaded.add(classInfo.getName()); + } + } else { + try { + @SuppressWarnings("unchecked") + final Parameter> parameter = (Parameter>) parameterInfo.get(); + result.add(parameter); + } catch (ClassNotFoundException e) { + classesNotLoaded.add(parameterInfo.getDeclaringMethod().getDeclaringClass().getName()); + } + } + } + return result; + } + public List findAnnotatedFields(Class annotation) { classesNotLoaded.clear(); List seen = new ArrayList(); @@ -1019,11 +1119,23 @@ public class AnnotationFinder implements infos.add(classInfo); classInfos.put(clazz.getName(), classInfo); for (Method method : clazz.getDeclaredMethods()) { - infos.add(new MethodInfo(classInfo, method)); + MethodInfo methodInfo = new MethodInfo(classInfo, method); + infos.add(methodInfo); + for (Annotation[] annotations : method.getParameterAnnotations()) { + for (int i = 0; i < annotations.length; i++) { + infos.add(new ParameterInfo(methodInfo, i)); + } + } } - for (Constructor constructor : clazz.getConstructors()) { - infos.add(new MethodInfo(classInfo, constructor)); + for (Constructor constructor : clazz.getConstructors()) { + MethodInfo methodInfo = new MethodInfo(classInfo, constructor); + infos.add(methodInfo); + for (Annotation[] annotations : constructor.getParameterAnnotations()) { + for (int i = 0; i < annotations.length; i++) { + infos.add(new ParameterInfo(methodInfo, i)); + } + } } for (Field field : clazz.getDeclaredFields()) { @@ -1306,6 +1418,7 @@ public class AnnotationFinder implements private final String descriptor; private final String name; private final List> parameterAnnotations = new ArrayList>(); + private final List parameters = new SingleLinkedList(); private Member method; public MethodInfo(ClassInfo info, Constructor constructor) { @@ -1362,6 +1475,10 @@ public class AnnotationFinder implements return parameterAnnotations.get(index); } + public List getParameters() { + return parameters; + } + public String getName() { return name; } @@ -1420,6 +1537,61 @@ public class AnnotationFinder implements } + public class ParameterInfo extends Annotatable implements Info { + private final MethodInfo declaringMethod; + private final int index; + private final List annotations = new ArrayList(); + private Parameter parameter; + + public ParameterInfo(MethodInfo parent, int index) { + super(); + this.declaringMethod = parent; + this.index = index; + } + + public ParameterInfo(MethodInfo parent, Parameter parameter) { + super(parameter); + this.declaringMethod = parent; + this.index = parameter.getIndex(); + this.parameter = parameter; + } + + public String getName() { + return Integer.toString(index); + } + + public Parameter get() throws ClassNotFoundException { + if (parameter == null) { + Member member = declaringMethod.get(); + if (member instanceof Method) { + parameter = Parameter.declaredBy((Method) member, index); + } else if (member instanceof Constructor) { + parameter = Parameter.declaredBy((Constructor) member, index); + + } + } + return parameter; + } + + @Override + public Annotation[] getDeclaredAnnotations() { + try { + return get().getDeclaredAnnotations(); + } catch (ClassNotFoundException e) { + return super.getDeclaredAnnotations(); + } + } + + public MethodInfo getDeclaringMethod() { + return declaringMethod; + } + + @Override + public String toString() { + return String.format("%s(arg%s)", declaringMethod, index); + } + } + public class FieldInfo extends Annotatable implements Info { private final String name; private final String type; @@ -1531,6 +1703,10 @@ public class AnnotationFinder implements this.info = info; } + public Info getInfo() { + return info; + } + @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { if (name.endsWith("package-info")) { @@ -1599,6 +1775,11 @@ public class AnnotationFinder implements List annotationInfos = methodInfo.getParameterAnnotations(param); AnnotationInfo annotationInfo = new AnnotationInfo(desc); annotationInfos.add(annotationInfo); + + ParameterInfo parameterInfo = new ParameterInfo(methodInfo, param); + methodInfo.getParameters().add(parameterInfo); + index(annotationInfo, parameterInfo); + return new InfoBuildingVisitor(annotationInfo); } } Added: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/Parameter.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/Parameter.java?rev=1438661&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/Parameter.java (added) +++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/Parameter.java Fri Jan 25 19:38:20 2013 @@ -0,0 +1,236 @@ +/* + * 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.xbean.finder; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +public abstract class Parameter implements AnnotatedElement { + private final E declaringExecutable; + private final int index; + + private Parameter(E declaringExecutable, int index) { + super(); + if (declaringExecutable == null) { + throw new NullPointerException("declaringExecutable"); + } + this.declaringExecutable = declaringExecutable; + if (index < 0) { + throw new IndexOutOfBoundsException(Integer.toString(index)); + } + this.index = index; + } + + public E getDeclaringExecutable() { + return declaringExecutable; + } + + public int getIndex() { + return index; + } + + public T getAnnotation(Class annotationClass) { + for (Annotation annotation : getAnnotations()) { + if (annotationClass.equals(annotation.annotationType())) { + @SuppressWarnings("unchecked") + final T result = (T) annotation; + return result; + } + } + return null; + } + + public Annotation[] getAnnotations() { + return getDeclaredAnnotations(); + } + + public Annotation[] getDeclaredAnnotations() { + return getParameterAnnotations()[index]; + } + + public boolean isAnnotationPresent(Class annotationClass) { + return getAnnotation(annotationClass) != null; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Parameter == false) { + return false; + } + Parameter p = (Parameter) o; + return declaringExecutable.equals(p.declaringExecutable) && index == p.index; + } + + @Override + public int hashCode() { + int result = declaringExecutable.hashCode() << 4; + result |= index; + return result; + } + + @Override + public String toString() { + return String.format("Parameter[index %s of %s]", index, declaringExecutable); + } + + protected abstract Annotation[][] getParameterAnnotations(); + + public static Parameter> declaredBy(Constructor ctor, int index) { + return new Parameter>(ctor, index) { + + @Override + protected Annotation[][] getParameterAnnotations() { + return getDeclaringExecutable().getParameterAnnotations(); + } + }; + } + + public static Parameter declaredBy(Method method, int index) { + return new Parameter(method, index) { + + @Override + protected Annotation[][] getParameterAnnotations() { + return getDeclaringExecutable().getParameterAnnotations(); + } + }; + } +} +/* + * 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.xbean.finder; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +public abstract class Parameter implements AnnotatedElement { + private final E declaringExecutable; + private final int index; + + private Parameter(E declaringExecutable, int index) { + super(); + if (declaringExecutable == null) { + throw new NullPointerException("declaringExecutable"); + } + this.declaringExecutable = declaringExecutable; + if (index < 0) { + throw new IndexOutOfBoundsException(Integer.toString(index)); + } + this.index = index; + } + + public E getDeclaringExecutable() { + return declaringExecutable; + } + + public int getIndex() { + return index; + } + + public T getAnnotation(Class annotationClass) { + for (Annotation annotation : getAnnotations()) { + if (annotationClass.equals(annotation.annotationType())) { + @SuppressWarnings("unchecked") + final T result = (T) annotation; + return result; + } + } + return null; + } + + public Annotation[] getAnnotations() { + return getDeclaredAnnotations(); + } + + public Annotation[] getDeclaredAnnotations() { + return getParameterAnnotations()[index]; + } + + public boolean isAnnotationPresent(Class annotationClass) { + return getAnnotation(annotationClass) != null; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Parameter == false) { + return false; + } + Parameter p = (Parameter) o; + return declaringExecutable.equals(p.declaringExecutable) && index == p.index; + } + + @Override + public int hashCode() { + int result = declaringExecutable.hashCode() << 4; + result |= index; + return result; + } + + @Override + public String toString() { + return String.format("Parameter[index %s of %s]", index, declaringExecutable); + } + + protected abstract Annotation[][] getParameterAnnotations(); + + public static Parameter> declaredBy(Constructor ctor, int index) { + return new Parameter>(ctor, index) { + + @Override + protected Annotation[][] getParameterAnnotations() { + return getDeclaringExecutable().getParameterAnnotations(); + } + }; + } + + public static Parameter declaredBy(Method method, int index) { + return new Parameter(method, index) { + + @Override + protected Annotation[][] getParameterAnnotations() { + return getDeclaringExecutable().getParameterAnnotations(); + } + }; + } +} Propchange: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/Parameter.java ------------------------------------------------------------------------------ svn:eol-style = native Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/AnnotatedParametersTest.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/AnnotatedParametersTest.java?rev=1438661&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/AnnotatedParametersTest.java (added) +++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/AnnotatedParametersTest.java Fri Jan 25 19:38:20 2013 @@ -0,0 +1,122 @@ +/* + * 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.xbean.finder; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.List; + +import org.acme.NotAnnotated; +import org.acme.bar.FullyAnnotated; +import org.acme.bar.ParamA; +import org.apache.xbean.finder.archive.ClassesArchive; +import org.junit.Test; + +public class AnnotatedParametersTest { + + @Test + public void testFindAnnotatedMethodParameters() { + final AnnotationFinder finder = new AnnotationFinder(new ClassesArchive(FullyAnnotated.class, NotAnnotated.class)); + List> methodParameters = finder.findAnnotatedMethodParameters(ParamA.class); + assertEquals(1, methodParameters.size()); + Parameter parameter = methodParameters.get(0); + assertEquals(0, parameter.getIndex()); + assertEquals(FullyAnnotated.class, parameter.getDeclaringExecutable().getDeclaringClass()); + assertEquals("setMoreStrings", parameter.getDeclaringExecutable().getName()); + assertEquals(1, parameter.getDeclaringExecutable().getParameterTypes().length); + assertEquals(String[][].class, parameter.getDeclaringExecutable().getParameterTypes()[0]); + assertTrue(parameter.isAnnotationPresent(ParamA.class)); + } + + @Test + public void testFindAnnotatedConstructorParameters() { + final AnnotationFinder finder = new AnnotationFinder(new ClassesArchive(FullyAnnotated.class, NotAnnotated.class)); + List>> constructorParameters = finder.findAnnotatedConstructorParameters(ParamA.class); + assertEquals(1, constructorParameters.size()); + Parameter> parameter = constructorParameters.get(0); + assertEquals(0, parameter.getIndex()); + assertEquals(FullyAnnotated.class, parameter.getDeclaringExecutable().getDeclaringClass()); + assertEquals(2, parameter.getDeclaringExecutable().getParameterTypes().length); + assertEquals(String.class, parameter.getDeclaringExecutable().getParameterTypes()[0]); + assertEquals(int.class, parameter.getDeclaringExecutable().getParameterTypes()[1]); + assertTrue(parameter.isAnnotationPresent(ParamA.class)); + } +} +/* + * 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.xbean.finder; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.List; + +import org.acme.NotAnnotated; +import org.acme.bar.FullyAnnotated; +import org.acme.bar.ParamA; +import org.apache.xbean.finder.archive.ClassesArchive; +import org.junit.Test; + +public class AnnotatedParametersTest { + + @Test + public void testFindAnnotatedMethodParameters() { + final AnnotationFinder finder = new AnnotationFinder(new ClassesArchive(FullyAnnotated.class, NotAnnotated.class)); + List> methodParameters = finder.findAnnotatedMethodParameters(ParamA.class); + assertEquals(1, methodParameters.size()); + Parameter parameter = methodParameters.get(0); + assertEquals(0, parameter.getIndex()); + assertEquals(FullyAnnotated.class, parameter.getDeclaringExecutable().getDeclaringClass()); + assertEquals("setMoreStrings", parameter.getDeclaringExecutable().getName()); + assertEquals(1, parameter.getDeclaringExecutable().getParameterTypes().length); + assertEquals(String[][].class, parameter.getDeclaringExecutable().getParameterTypes()[0]); + assertTrue(parameter.isAnnotationPresent(ParamA.class)); + } + + @Test + public void testFindAnnotatedConstructorParameters() { + final AnnotationFinder finder = new AnnotationFinder(new ClassesArchive(FullyAnnotated.class, NotAnnotated.class)); + List>> constructorParameters = finder.findAnnotatedConstructorParameters(ParamA.class); + assertEquals(1, constructorParameters.size()); + Parameter> parameter = constructorParameters.get(0); + assertEquals(0, parameter.getIndex()); + assertEquals(FullyAnnotated.class, parameter.getDeclaringExecutable().getDeclaringClass()); + assertEquals(2, parameter.getDeclaringExecutable().getParameterTypes().length); + assertEquals(String.class, parameter.getDeclaringExecutable().getParameterTypes()[0]); + assertEquals(int.class, parameter.getDeclaringExecutable().getParameterTypes()[1]); + assertTrue(parameter.isAnnotationPresent(ParamA.class)); + } +} Propchange: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/AnnotatedParametersTest.java ------------------------------------------------------------------------------ svn:eol-style = native