Author: musachy Date: Fri Mar 2 21:23:01 2007 New Revision: 514081 URL: http://svn.apache.org/viewvc?view=rev&rev=514081 Log: WW-1675 Modify Struts Annotations to scan compiled classes for annotations @StrutsTagSkipInheritance was added to stop class hierarchy scanning for Struts tag annotations
Modified: struts/maven/trunk/struts-annotations/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java Modified: struts/maven/trunk/struts-annotations/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java URL: http://svn.apache.org/viewvc/struts/maven/trunk/struts-annotations/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java?view=diff&rev=514081&r1=514080&r2=514081 ============================================================================== --- struts/maven/trunk/struts-annotations/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java (original) +++ struts/maven/trunk/struts-annotations/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java Fri Mar 2 21:23:01 2007 @@ -20,11 +20,19 @@ */ package org.apache.struts.annotations.taglib.apt; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.OutputStreamWriter; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.Collection; import java.util.HashMap; import java.util.TreeMap; @@ -61,6 +69,7 @@ public class TagAnnotationProcessor implements AnnotationProcessor { public static final String TAG = "org.apache.struts2.views.annotations.StrutsTag"; public static final String TAG_ATTRIBUTE = "org.apache.struts2.views.annotations.StrutsTagAttribute"; + public static final String TAG_SKIP_HIERARCHY = "org.apache.struts2.views.annotations.StrutsTagSkipInheritance"; private AnnotationProcessorEnvironment environment; private AnnotationTypeDeclaration tagDeclaration; @@ -113,7 +122,6 @@ tagAttributeDeclaration); // create Attribute and apply values found TagAttribute attribute = new TagAttribute(); - attribute.setDescription((String) values.get("description")); String name = (String) values.get("name"); if (name == null || name.length() == 0) { // get name from method @@ -122,11 +130,8 @@ .charAt(3))) + methodName.substring(4); } - attribute.setName(name); - attribute.setRequired((Boolean) values.get("required")); - attribute.setRtexprvalue((Boolean) values.get("rtexprvalue")); - attribute.setDefaultValue((String) values.get("defaultValue")); - attribute.setType((String) values.get("type")); + values.put("name", name); + populateTagAttributes(attribute, values); // add to map Tag parentTag = tags.get(typeName); if (parentTag != null) @@ -153,23 +158,74 @@ saveTemplates(); } + private void populateTagAttributes(TagAttribute attribute, Map<String, Object> values) { + attribute.setRequired((Boolean) values.get("required")); + attribute.setRtexprvalue((Boolean) values.get("rtexprvalue")); + attribute.setDefaultValue((String) values.get("defaultValue")); + attribute.setType((String) values.get("type")); + attribute.setDescription((String) values.get("description")); + attribute.setName((String) values.get("name")); + } + private void processHierarchy(Tag tag) { try { Class clazz = Class.forName(tag.getDeclaredType()); - while ((clazz = clazz.getSuperclass()) != null) { + //skip hierarchy processing if the class is marked with the skip annotation + while(getAnnotation(TAG_SKIP_HIERARCHY, clazz.getAnnotations()) == null + && ((clazz = clazz.getSuperclass()) != null)) { Tag parentTag = tags.get(clazz.getName()); // copy parent annotations to this tag - if (parentTag != null) { - for (TagAttribute attribute : parentTag.getAttributes()) { + if(parentTag != null) { + for(TagAttribute attribute : parentTag.getAttributes()) { + tag.addTagAttribute(attribute); + } + } else { + // Maybe the parent class is already compiled + addTagAttributesFromParent(tag, clazz); + } + } + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + private void addTagAttributesFromParent(Tag tag, Class clazz) throws ClassNotFoundException { + try { + BeanInfo info = Introspector.getBeanInfo(clazz); + PropertyDescriptor[] props = info.getPropertyDescriptors(); + + //iterate over class fields + for(int i = 0; i < props.length; ++i) { + PropertyDescriptor prop = props[i]; + Method writeMethod = prop.getWriteMethod(); + //make sure it is public + if(writeMethod != null && Modifier.isPublic(writeMethod.getModifiers())) { + //can't use the genertic getAnnotation 'cause the class it not on this jar + Annotation annotation = getAnnotation(TAG_ATTRIBUTE, writeMethod.getAnnotations()); + if(annotation != null) { + Map<String, Object> values = getValues(annotation); + //create tag + TagAttribute attribute = new TagAttribute(); + values.put("name", prop.getName()); + populateTagAttributes(attribute, values); tag.addTagAttribute(attribute); } } + } - } catch (ClassNotFoundException e) { + } catch(Exception e) { throw new RuntimeException(e); } } + private Annotation getAnnotation(String typeName, Annotation[] annotations) { + for(int i = 0; i < annotations.length; i++) { + if(annotations[i].annotationType().getName().equals(typeName)) + return annotations[i]; + } + return null; + } + private void checkOptions() { if (getOption("tlibVersion") == null) throw new IllegalArgumentException("'tlibVersion' is missing"); @@ -340,7 +396,7 @@ /** * Get values of annotation - * + * * @param declaration The annotation declaration * @param type * The type of the annotation @@ -375,6 +431,35 @@ String name = annotationType.getSimpleName(); if (!values.containsKey(name)) values.put(name, value.getValue()); + } + } + + return values; + } + + /** + * Get values of annotation + * + * @param annotation The annotation + * @return name->value map of annotation values + * @throws IntrospectionException + * @throws InvocationTargetException + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + private Map<String, Object> getValues(Annotation annotation) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Map<String, Object> values = new TreeMap<String, Object>(); + //if the tag classes were on this project we could just cast to the right type + //but they are needed on core + Class annotationType = annotation.annotationType(); + + Method[] methods = annotationType.getMethods(); + //iterate over class fields + for(int i = 0; i < methods.length; ++i) { + Method method = methods[i]; + if(method != null && method.getParameterTypes().length == 0) { + Object value = method.invoke(annotation, new Object[0]); + values.put(method.getName(), value); } }