Uses annotation processor instead of apt
diff --git a/src/main/java/org/apache/struts/annotations/taglib/apt/TLDAnnotationProcessorFactory.java b/src/main/java/org/apache/struts/annotations/taglib/apt/TLDAnnotationProcessorFactory.java
deleted file mode 100644
index 663d6ed..0000000
--- a/src/main/java/org/apache/struts/annotations/taglib/apt/TLDAnnotationProcessorFactory.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * $Id:  $
- *
- * 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.struts.annotations.taglib.apt;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Set;
-
-import com.sun.mirror.apt.AnnotationProcessor;
-import com.sun.mirror.apt.AnnotationProcessorEnvironment;
-import com.sun.mirror.apt.AnnotationProcessorFactory;
-import com.sun.mirror.apt.AnnotationProcessors;
-import com.sun.mirror.declaration.AnnotationTypeDeclaration;
-
-public class TLDAnnotationProcessorFactory implements
-        AnnotationProcessorFactory {
-
-    /**
-     * Returns a TLD annotation processor.
-     * 
-     * @return An annotation processor for note annotations if requested,
-     *         otherwise, returns the NO_OP annotation processor.
-     */
-    public AnnotationProcessor getProcessorFor(
-            Set<AnnotationTypeDeclaration> declarations,
-            AnnotationProcessorEnvironment env) {
-        AnnotationProcessor result;
-        if (declarations.isEmpty()) {
-            result = AnnotationProcessors.NO_OP;
-        } else {
-            result = new TagAnnotationProcessor(env);
-        }
-        return result;
-    }
-
-    /**
-     * This factory builds a processor for Tag and TagAttribute
-     * 
-     * @return a collection containing StutsTag and StrutsTagAttribute
-     */
-    public Collection<String> supportedAnnotationTypes() {
-        return Arrays.asList(TagAnnotationProcessor.TAG,
-                TagAnnotationProcessor.TAG_ATTRIBUTE,
-                TagAnnotationProcessor.TAG_SKIP_HIERARCHY);
-    }
-
-    /**
-     * Options used to generate the TLD
-     * 
-     * @return an empty list.
-     */
-    public Collection<String> supportedOptions() {
-        return Arrays.asList("-AoutFile", "-AtlibVersion", "-AjspVersion",
-                "-AshortName", "-Auri", "-Adescription", "-AdisplayName",
-                "-outTemplatesDir");
-    }
-}
diff --git a/src/main/java/org/apache/struts/annotations/taglib/apt/Tag.java b/src/main/java/org/apache/struts/annotations/taglib/apt/Tag.java
index 175bd46..6993830 100644
--- a/src/main/java/org/apache/struts/annotations/taglib/apt/Tag.java
+++ b/src/main/java/org/apache/struts/annotations/taglib/apt/Tag.java
@@ -34,8 +34,8 @@
     private boolean allowDynamicAttributes;
     private boolean include = true;
     private String declaredType;
-    private Map<String, TagAttribute> attributes = new TreeMap<String, TagAttribute>();
-    private List<String> skipAttributes = new ArrayList<String>();
+    private Map<String, TagAttribute> attributes = new TreeMap<>();
+    private List<String> skipAttributes = new ArrayList<>();
     
     public String getDescription() {
         return description;
diff --git a/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java b/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java
index d3a1bbb..7134291 100644
--- a/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java
+++ b/src/main/java/org/apache/struts/annotations/taglib/apt/TagAnnotationProcessor.java
@@ -20,25 +20,29 @@
  */
 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.List;
-import java.util.TreeMap;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
 
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.NoType;
+import javax.lang.model.util.ElementFilter;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.transform.OutputKeys;
@@ -53,79 +57,53 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.Text;
 
-import com.sun.mirror.apt.AnnotationProcessor;
-import com.sun.mirror.apt.AnnotationProcessorEnvironment;
-import com.sun.mirror.declaration.AnnotationMirror;
-import com.sun.mirror.declaration.AnnotationTypeDeclaration;
-import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
-import com.sun.mirror.declaration.AnnotationValue;
-import com.sun.mirror.declaration.Declaration;
-import com.sun.mirror.declaration.MethodDeclaration;
-import com.sun.mirror.declaration.TypeDeclaration;
-
 import freemarker.template.Configuration;
 import freemarker.template.DefaultObjectWrapper;
 import freemarker.template.Template;
 
-public class TagAnnotationProcessor implements AnnotationProcessor {
+@SupportedAnnotationTypes({TagAnnotationProcessor.TAG, TagAnnotationProcessor.TAG_ATTRIBUTE, TagAnnotationProcessor.TAG_SKIP_HIERARCHY})
+public class TagAnnotationProcessor extends AbstractProcessor {
     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;
-    private AnnotationTypeDeclaration tagAttributeDeclaration;
-    private AnnotationTypeDeclaration skipDeclaration;
-    private Map<String, Tag> tags = new TreeMap<String, Tag>();
+    private Map<String, Tag> tags = new TreeMap<>();
 
-    public TagAnnotationProcessor(AnnotationProcessorEnvironment env) {
-        environment = env;
-        tagDeclaration = (AnnotationTypeDeclaration) environment
-                .getTypeDeclaration(TAG);
-        tagAttributeDeclaration = (AnnotationTypeDeclaration) environment
-                .getTypeDeclaration(TAG_ATTRIBUTE);
-        skipDeclaration = (AnnotationTypeDeclaration) environment
-                .getTypeDeclaration(TAG_SKIP_HIERARCHY);
-    }
-
-    public void process() {
+    @Override
+	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
         // make sure all paramters were set
         checkOptions();
 
         // tags
-        Collection<Declaration> tagDeclarations = environment
-                .getDeclarationsAnnotatedWith(tagDeclaration);
-        Collection<Declaration> attributesDeclarations = environment
-                .getDeclarationsAnnotatedWith(tagAttributeDeclaration);
-        Collection<Declaration> skipDeclarations = environment
-                 .getDeclarationsAnnotatedWith(skipDeclaration);
+        TypeElement tagAnnotationType = processingEnv.getElementUtils().getTypeElement(TAG);
+        TypeElement attributeAnnotationType = processingEnv.getElementUtils().getTypeElement(TAG_ATTRIBUTE);
+        TypeElement skipAnnotationType = processingEnv.getElementUtils().getTypeElement(TAG_SKIP_HIERARCHY);
+		Set<? extends javax.lang.model.element.Element> tagDeclarations = roundEnv.getElementsAnnotatedWith(tagAnnotationType);
+		Set<? extends javax.lang.model.element.Element> attributesDeclarations = roundEnv.getElementsAnnotatedWith(attributeAnnotationType);
+		Set<? extends javax.lang.model.element.Element> skipDeclarations = roundEnv.getElementsAnnotatedWith(skipAnnotationType);
 
         // find Tags
-        for (Declaration declaration : tagDeclarations) {
-            // type
-            TypeDeclaration typeDeclaration = (TypeDeclaration) declaration;
-            String typeName = typeDeclaration.getQualifiedName();
-            Map<String, Object> values = getValues(typeDeclaration,
-                    tagDeclaration);
-            // create Tag and apply values found
-            Tag tag = new Tag();
+    	for (javax.lang.model.element.Element element : tagDeclarations) {
+			Map<String, Object> values = getValues(element, tagAnnotationType);
+			TypeElement type = (TypeElement) element;
+			Tag tag = new Tag();
             tag.setDescription((String) values.get("description"));
             tag.setName((String) values.get("name"));
             tag.setTldBodyContent((String) values.get("tldBodyContent"));
             tag.setTldTagClass((String) values.get("tldTagClass"));
-            tag.setDeclaredType(typeName);
+            tag.setDeclaredType(type.getQualifiedName().toString());
             tag.setAllowDynamicAttributes((Boolean) values.get("allowDynamicAttributes"));
             // add to map
-            tags.put(typeName, tag);
-        }
+            tags.put(type.getQualifiedName().toString(), tag);
+		}
 
         //find attributes to be skipped
-        for (Declaration declaration : skipDeclarations) {
+        for (javax.lang.model.element.Element declaration : skipDeclarations) {
             //types will be ignored when hierarchy is scanned
-            if (declaration instanceof MethodDeclaration) {
-                MethodDeclaration methodDeclaration = (MethodDeclaration) declaration;
-                String typeName = methodDeclaration.getDeclaringType().getQualifiedName();
-                String methodName = methodDeclaration.getSimpleName();
+            if (declaration instanceof ExecutableElement) {
+            	ExecutableElement methodDeclaration = (ExecutableElement) declaration;
+                String typeName = ((TypeElement) methodDeclaration.getEnclosingElement()).getQualifiedName().toString();
+                String methodName = methodDeclaration.getSimpleName().toString();
                 String name = String.valueOf(Character.toLowerCase(methodName
                     .charAt(3)))
                     + methodName.substring(4);
@@ -138,19 +116,18 @@
         }
 
         // find Tags Attributes
-        for (Declaration declaration : attributesDeclarations) {
+        for (javax.lang.model.element.Element declaration : attributesDeclarations) {
             // type
-            MethodDeclaration methodDeclaration = (MethodDeclaration) declaration;
-            String typeName = methodDeclaration.getDeclaringType()
-                    .getQualifiedName();
+        	ExecutableElement methodDeclaration = (ExecutableElement) declaration;
+        	String typeName = ((TypeElement) methodDeclaration.getEnclosingElement()).getQualifiedName().toString();
             Map<String, Object> values = getValues(methodDeclaration,
-                    tagAttributeDeclaration);
+                    attributeAnnotationType);
             // create Attribute and apply values found
             TagAttribute attribute = new TagAttribute();
             String name = (String) values.get("name");
             if (name == null || name.length() == 0) {
                 // get name from method
-                String methodName = methodDeclaration.getSimpleName();
+                String methodName = methodDeclaration.getSimpleName().toString();
                 name = String.valueOf(Character.toLowerCase(methodName
                         .charAt(3)))
                         + methodName.substring(4);
@@ -159,9 +136,9 @@
             populateTagAttributes(attribute, values);
             // add to map
             Tag parentTag = tags.get(typeName);
-            if (parentTag != null)
+            if (parentTag != null){
                 tags.get(typeName).addTagAttribute(attribute);
-            else {
+            }else {
                 // an abstract or base class
                 parentTag = new Tag();
                 parentTag.setDeclaredType(typeName);
@@ -172,7 +149,7 @@
         }
 
         // we can't process the hierarchy on the first pass because
-        // apt does not garantees that the base classes will be processed
+        // apt does not guarantee that the base classes will be processed
         // before their subclasses
         for (Map.Entry<String, Tag> entry : tags.entrySet()) {
             processHierarchy(entry.getValue());
@@ -181,9 +158,10 @@
         // save
         saveAsXml();
         saveTemplates();
+        return true;
     }
 
-    private void populateTagAttributes(TagAttribute attribute, Map<String, Object> values) {
+    private static 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"));
@@ -193,65 +171,55 @@
     }
 
     private void processHierarchy(Tag tag) {
-        try {
-            Class clazz = Class.forName(tag.getDeclaredType());
-            List<String> skipAttributes = tag.getSkipAttributes();
-            //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(!skipAttributes.contains(attribute.getName()))
-                            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();
-            List<String> skipAttributes = tag.getSkipAttributes();
-
-            //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 && !skipAttributes.contains(prop.getName())) {
-                        Map<String, Object> values = getValues(annotation);
-                        //create tag
-                        TagAttribute attribute = new TagAttribute();
-                        values.put("name", prop.getName());
-                        populateTagAttributes(attribute, values);
+    	TypeElement type = processingEnv.getElementUtils().getTypeElement(tag.getDeclaredType());
+    	List<String> skipAttributes = tag.getSkipAttributes();
+    	while (type !=null && !(type instanceof NoType) && getAnnotation(type, TAG_SKIP_HIERARCHY) == null) {
+    		Tag parentTag = tags.get(type.getQualifiedName().toString());
+            // copy parent annotations to this tag
+            if(parentTag != null) {
+                for(TagAttribute attribute : parentTag.getAttributes()) {
+                    if(!skipAttributes.contains(attribute.getName())){
                         tag.addTagAttribute(attribute);
                     }
                 }
-
+            } else {
+                // Maybe the parent class is already compiled
+                addTagAttributesFromParent(tag, type);
             }
-        } catch(Exception e) {
-            throw new RuntimeException(e);
-        }
+            type = (TypeElement) processingEnv.getTypeUtils().asElement(type.getSuperclass());
+    	}
     }
 
-    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];
-        }
+    private void addTagAttributesFromParent(Tag tag, TypeElement type) {
+    	for (ExecutableElement method : ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(type))) {
+    		AnnotationMirror annotation = getAnnotation(method, TAG_ATTRIBUTE);
+			if (method.getModifiers().contains(Modifier.PUBLIC) && annotation != null) {
+				String name = String.valueOf(Character.toLowerCase(method.getSimpleName()
+	                    .charAt(3)))
+	                    + method.getSimpleName().subSequence(4, method.getSimpleName().length());
+    			if (!tag.getSkipAttributes().contains(name)) {
+    				Map<String, Object> values = new HashMap<>();
+    				for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : processingEnv.getElementUtils().getElementValuesWithDefaults(annotation).entrySet()) {
+    					values.put(entry.getKey().getSimpleName().toString(), entry.getValue().getValue());
+    				}
+    				TagAttribute attribute = new TagAttribute();
+                    populateTagAttributes(attribute, values);
+                    attribute.setName(name);
+                    tag.addTagAttribute(attribute);
+    			}
+    		}
+    	}
+    }
+
+    private AnnotationMirror getAnnotation(javax.lang.model.element.Element element, String annotationName) {
+    	TypeElement annotation = processingEnv.getElementUtils().getTypeElement(annotationName);
+    	if (element != null && element.getAnnotationMirrors() != null) {
+    	for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
+    		if (mirror.getAnnotationType().asElement().equals(annotation)) {
+    			return mirror;
+    		}
+    	}
+    	}
         return null;
     }
 
@@ -288,16 +256,12 @@
             for (Tag tag : tags.values()) {
                 if (tag.isInclude()) {
                     // model
-                    HashMap<String, Tag> root = new HashMap<String, Tag>();
+                    HashMap<String, Tag> root = new HashMap<>();
                     root.put("tag", tag);
 
-                    // save file
-                    BufferedWriter writer = new BufferedWriter(new FileWriter(
-                            new File(rootDir, tag.getName() + ".html")));
-                    try {
-                        template.process(root, writer);
-                    } finally {
-                        writer.close();
+                    try (BufferedWriter writer = new BufferedWriter(new FileWriter(
+                            new File(rootDir, tag.getName() + ".html")))){
+                    	template.process(root, writer);
                     }
                 }
             }
@@ -373,10 +337,10 @@
         // there is a bug in the 1.5 apt implementation:
         // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6258929
         // this is a hack-around
-        if (environment.getOptions().containsKey(name))
-            return environment.getOptions().get(name);
-
-        for (Map.Entry<String, String> entry : environment.getOptions()
+        if (processingEnv.getOptions().containsKey(name)){
+            return processingEnv.getOptions().get(name);
+        }
+        for (Map.Entry<String, String> entry : processingEnv.getOptions()
                 .entrySet()) {
             String key = entry.getKey();
             String[] splitted = key.split("=");
@@ -386,7 +350,7 @@
         return null;
     }
 
-    private void createElement(Document doc, Element tagLibElement, Tag tag) {
+    private static void createElement(Document doc, Element tagLibElement, Tag tag) {
         Element tagElement = doc.createElement("tag");
         tagLibElement.appendChild(tagElement);
         appendTextNode(doc, tagElement, "description", tag.getDescription(),
@@ -405,8 +369,7 @@
         appendTextNode(doc, tagElement, "dynamic-attributes", String.valueOf(tag.isAllowDynamicAttributes()), false);
     }
 
-    private void createElement(Document doc, Element tagElement,
-            TagAttribute attribute) {
+    private static void createElement(Document doc, Element tagElement, TagAttribute attribute) {
         Element attributeElement = doc.createElement("attribute");
         tagElement.appendChild(attributeElement);
         appendTextNode(doc, attributeElement, "description", attribute
@@ -419,7 +382,7 @@
                 .valueOf(attribute.isRtexprvalue()), false);
     }
 
-    private void appendTextNode(Document doc, Element element, String name,
+    private static void appendTextNode(Document doc, Element element, String name,
             String text, boolean cdata) {
         Text textNode = cdata ? doc.createCDATASection(text) : doc
                 .createTextNode(text);
@@ -436,67 +399,22 @@
      *            The type of the annotation
      * @return name->value map of annotation values
      */
-    private Map<String, Object> getValues(Declaration declaration,
-            AnnotationTypeDeclaration type) {
-        Map<String, Object> values = new TreeMap<String, Object>();
-        Collection<AnnotationMirror> annotations = declaration
+    private Map<String, Object> getValues(javax.lang.model.element.Element element, TypeElement type) {
+        Map<String, Object> values = new TreeMap<>();
+        Collection<? extends AnnotationMirror> annotations = element
                 .getAnnotationMirrors();
         // iterate over the mirrors.
 
         for (AnnotationMirror mirror : annotations) {
             // if the mirror in this iteration is for our note declaration...
-            if (mirror.getAnnotationType().getDeclaration().equals(type)) {
-                for (AnnotationTypeElementDeclaration annotationType : mirror
-                        .getElementValues().keySet()) {
-                    Object value = mirror.getElementValues()
-                            .get(annotationType).getValue();
-                    Object defaultValue = annotationType.getDefaultValue();
-                    values.put(annotationType.getSimpleName(),
-                            value != null ? value : defaultValue);
+            if (mirror.getAnnotationType().asElement().equals(type)) {
+                for (Entry<? extends ExecutableElement, ? extends AnnotationValue> elementEntry : processingEnv.getElementUtils().getElementValuesWithDefaults(mirror).entrySet()) {
+                    values.put(elementEntry.getKey().getSimpleName().toString(), elementEntry.getValue().getValue());
                 }
             }
         }
 
-        // find default values...painful
-        for (AnnotationTypeElementDeclaration annotationType : type
-                .getMethods()) {
-            AnnotationValue value = annotationType.getDefaultValue();
-            if (value != null) {
-                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);
-            }
-        }
-
-        return values;
-    }
 }
diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..e3bb2d3
--- /dev/null
+++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+org.apache.struts.annotations.taglib.apt.TagAnnotationProcessor