Merge pull request #206 from lukaszlenart/scan-deeper

WW-4912: scan package-info and class at the same time
This commit is contained in:
Yasser Zamani
2018-01-30 13:17:09 +03:30
committed by GitHub
11 changed files with 203 additions and 15 deletions
@@ -18,9 +18,12 @@
*/
package com.opensymphony.xwork2.util;
import org.apache.commons.lang3.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
@@ -129,7 +132,7 @@ public class AnnotationUtils {
}
/**
* Returns the annotation on the given class or the package of the class. This searchs up the
* Returns the annotation on the given class or the package of the class. This searches up the
* class hierarchy and the package hierarchy for the closest match.
*
* @param <T> class type
@@ -154,4 +157,36 @@ public class AnnotationUtils {
return ann;
}
/**
* Returns a list of the annotation on the given class or the package of the class.
* This searches up the class hierarchy and the package hierarchy.
*
* @param <T> class type
* @param clazz The class to search for the annotation.
* @param annotationClass The Class of the annotation.
* @return List of the annotations or an empty list.
*/
public static <T extends Annotation> List<T> findAnnotations(Class<?> clazz, Class<T> annotationClass) {
List<T> anns = new ArrayList<>();
List<Class<?>> classes = new ArrayList<>();
classes.add(clazz);
classes.addAll(ClassUtils.getAllSuperclasses(clazz));
classes.addAll(ClassUtils.getAllInterfaces(clazz));
for (Class<?> aClass : classes) {
T ann = aClass.getAnnotation(annotationClass);
if (ann != null) {
anns.add(ann);
}
ann = aClass.getPackage().getAnnotation(annotationClass);
if (ann != null) {
anns.add(ann);
}
}
return anns;
}
}
@@ -19,14 +19,19 @@
package com.opensymphony.xwork2.util;
import com.opensymphony.xwork2.util.annotation.Dummy2Class;
import com.opensymphony.xwork2.util.annotation.Dummy3Class;
import com.opensymphony.xwork2.util.annotation.DummyClass;
import com.opensymphony.xwork2.util.annotation.DummyClassExt;
import com.opensymphony.xwork2.util.annotation.MyAnnotation;
import com.opensymphony.xwork2.util.annotation.MyAnnotation2;
import junit.framework.TestCase;
/**
* @author Dan Oxlade, dan d0t oxlade at gmail d0t c0m
*/
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.fest.assertions.Assertions.assertThat;
public class AnnotationUtilsTest extends TestCase {
public void testFindAnnotationOnClass() {
@@ -41,4 +46,25 @@ public class AnnotationUtilsTest extends TestCase {
assertEquals("package-test", ns.value());
}
public void testFindAnnotationOnParents() {
MyAnnotation2 ns = AnnotationUtils.findAnnotation(Dummy3Class.class, MyAnnotation2.class);
assertNotNull(ns);
assertEquals("abstract-abstract", ns.value());
}
public void testFindAnnotationsOnAll() {
List<MyAnnotation> annotations = AnnotationUtils.findAnnotations(DummyClassExt.class, MyAnnotation.class);
assertThat(annotations)
.isNotNull()
.isNotEmpty()
.hasSize(5);
Set<String> values = new HashSet<>();
for (MyAnnotation annotation : annotations) {
values.add(annotation.value());
}
assertThat(values).contains("class-test", "package-test", "interface-test", "package2-test");
}
}
@@ -0,0 +1,25 @@
/*
* 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 com.opensymphony.xwork2.util.annotation;
import com.opensymphony.xwork2.util.annotation.pkg1.AbstractDummyAction;
public class Dummy3Class extends AbstractDummyAction{
}
@@ -18,8 +18,10 @@
*/
package com.opensymphony.xwork2.util.annotation;
import com.opensymphony.xwork2.util.annotation.pkg2.Package2DummyInterface;
@MyAnnotation("class-test")
public class DummyClass {
public class DummyClass implements Package2DummyInterface {
public DummyClass() {
}
@@ -23,4 +23,6 @@ import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
String value() default "";
}
@@ -0,0 +1,25 @@
/*
* 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 com.opensymphony.xwork2.util.annotation.pkg1;
import com.opensymphony.xwork2.util.annotation.MyAnnotation2;
@MyAnnotation2("abstract-abstract")
public class AbstractAbstractDummyAction {
}
@@ -0,0 +1,22 @@
/*
* 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 com.opensymphony.xwork2.util.annotation.pkg1;
public class AbstractDummyAction extends AbstractAbstractDummyAction {
}
@@ -0,0 +1,25 @@
/*
* 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 com.opensymphony.xwork2.util.annotation.pkg2;
import com.opensymphony.xwork2.util.annotation.MyAnnotation;
@MyAnnotation("interface-test")
public interface Package2DummyInterface {
}
@@ -0,0 +1,23 @@
/*
* 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.
*/
@MyAnnotation("package2-test")
package com.opensymphony.xwork2.util.annotation.pkg2;
import com.opensymphony.xwork2.util.annotation.MyAnnotation;
@@ -749,13 +749,13 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
}
private Set<String> getAllowedMethods(Class<?> actionClass) {
AllowedMethods annotation = AnnotationUtils.findAnnotation(actionClass, AllowedMethods.class);
if (annotation == null) {
List<AllowedMethods> annotations = AnnotationUtils.findAnnotations(actionClass, AllowedMethods.class);
if (annotations == null || annotations.isEmpty()) {
return Collections.emptySet();
} else {
Set<String> methods = new HashSet<>();
for (String method : annotation.value()) {
methods.add(method);
for (AllowedMethods allowedMethods : annotations) {
methods.addAll(Arrays.asList(allowedMethods.value()));
}
return methods;
}
@@ -924,7 +924,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
String actionMethod, Action annotation, Set<String> allowedMethods) {
String className = actionClass.getName();
if (annotation != null) {
actionName = annotation.value() != null && annotation.value().equals(Action.DEFAULT_VALUE) ? actionName : annotation.value();
actionName = annotation.value().equals(Action.DEFAULT_VALUE) ? actionName : annotation.value();
actionName = StringUtils.contains(actionName, "/") && !slashesInActionNames ? StringUtils.substringAfterLast(actionName, "/") : actionName;
if(!Action.DEFAULT_VALUE.equals(annotation.className())){
className = annotation.className();
@@ -960,7 +960,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
actionConfig.addParams(StringTools.createParameterMap(annotation.params()));
//add exception mappings from annotation
if (annotation != null && annotation.exceptionMappings() != null)
if (annotation != null)
actionConfig.addExceptionMappings(buildExceptionMappings(annotation.exceptionMappings(), actionName));
//add exception mapping from class
@@ -997,8 +997,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
exceptionMapping.result(), actionName);
ExceptionMappingConfig.Builder builder = new ExceptionMappingConfig.Builder(null, exceptionMapping
.exception(), exceptionMapping.result());
if (exceptionMapping.params() != null)
builder.addParams(StringTools.createParameterMap(exceptionMapping.params()));
builder.addParams(StringTools.createParameterMap(exceptionMapping.params()));
exceptionMappings.add(builder.build());
}
@@ -544,10 +544,14 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
assertEquals("struts-default", pkgConfig.getParents().get(0).getName());
ActionConfig actionConfig = pkgConfig.getActionConfigs().get("class-level-allowed-methods");
assertEquals(actionConfig.getAllowedMethods().size(), 5);
assertEquals(7, actionConfig.getAllowedMethods().size());
assertTrue(actionConfig.getAllowedMethods().contains("execute"));
assertTrue(actionConfig.getAllowedMethods().contains("end"));
assertTrue(actionConfig.getAllowedMethods().contains("input"));
assertTrue(actionConfig.getAllowedMethods().contains("cancel"));
assertTrue(actionConfig.getAllowedMethods().contains("start"));
assertTrue(actionConfig.getAllowedMethods().contains("home"));
assertTrue(actionConfig.getAllowedMethods().contains("browse"));
/* org.apache.struts2.convention.actions.allowedmethods.sub package level */
pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.allowedmethods.sub#struts-default#/allowedmethods/sub");