WW-2990 support result inheritance

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@743811 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Musachy Barroso
2009-02-12 17:13:21 +00:00
parent 9a1aa35714
commit cf7b322bd5
10 changed files with 306 additions and 21 deletions
@@ -188,21 +188,33 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
actionClass, resultsByExtension);
}
//get inherited @Results and @Result
for (Class<?> clazz : ReflectionTools.getClassHierarchy(actionClass)) {
createResultsFromAnnotations(clazz, packageConfig, defaultResultPath, results, resultsByExtension);
}
return results;
}
/**
* Creates results from @Results and @Result annotations
*/
protected void createResultsFromAnnotations(Class<?> actionClass, PackageConfig packageConfig, String defaultResultPath,
Map<String, ResultConfig> results, Map<String, ResultTypeConfig> resultsByExtension) {
Results resultsAnn = actionClass.getAnnotation(Results.class);
if (resultsAnn != null) {
createFromAnnotations(results, defaultResultPath, packageConfig, resultsAnn.value(),
actionClass, resultsByExtension);
actionClass, resultsByExtension);
}
Result resultAnn = actionClass.getAnnotation(Result.class);
if (resultAnn != null) {
createFromAnnotations(results, defaultResultPath, packageConfig, new Result[]{resultAnn},
actionClass, resultsByExtension);
actionClass, resultsByExtension);
}
return results;
}
/**
* Creates any result types from the resources available in the web application. This scans the
* web application resources using the servlet context.
@@ -22,6 +22,8 @@ package org.apache.struts2.convention;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.ArrayList;
/**
* <p>
@@ -62,4 +64,19 @@ public class ReflectionTools {
throw new RuntimeException(e);
}
}
/**
* Return the list of parent classes in order (Object will be at index 0)
* @param clazz class to process
* @return hierarchy of classes
*/
public static List<Class<?>> getClassHierarchy(Class<?> clazz) {
List<Class<?>> classes = new ArrayList<Class<?>>();
while (clazz != null) {
classes.add(0, clazz);
clazz = clazz.getSuperclass();
}
return classes;
}
}
@@ -33,6 +33,9 @@ import org.apache.struts2.convention.actions.result.ActionLevelResultAction;
import org.apache.struts2.convention.actions.result.ActionLevelResultsAction;
import org.apache.struts2.convention.actions.result.ClassLevelResultAction;
import org.apache.struts2.convention.actions.result.ClassLevelResultsAction;
import org.apache.struts2.convention.actions.result.InheritedResultExtends;
import org.apache.struts2.convention.actions.result.InheritedResultsExtends;
import org.apache.struts2.convention.actions.result.OverrideInheritedResultExtends;
import org.apache.struts2.convention.actions.resultpath.ClassLevelResultPathAction;
import org.apache.struts2.convention.annotation.Action;
import org.easymock.EasyMock;
@@ -109,7 +112,7 @@ public class DefaultResultMapBuilderTest extends TestCase {
PackageConfig packageConfig = createPackageConfigBuilder("/namespace");
this.conventionsService = new ConventionsServiceImpl("/WEB-INF/location");
this.conventionsService = new ConventionsServiceImpl("/WEB-INF/location");
DefaultResultMapBuilder builder = new DefaultResultMapBuilder(context, container, "dispatcher,velocity,freemarker");
Map<String, ResultConfig> results = builder.build(NoAnnotationAction.class, null, "no-annotation", packageConfig);
assertEquals(4, results.size());
@@ -153,6 +156,54 @@ public class DefaultResultMapBuilderTest extends TestCase {
EasyMock.verify(context);
}
public void testClassLevelInheritedSingleResultAnnotation() throws Exception {
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
// Setup some mock jsps
Set<String> resources = new HashSet<String>();
EasyMock.expect(context.getResourcePaths("/WEB-INF/location/namespace/")).andReturn(resources);
EasyMock.replay(context);
PackageConfig packageConfig = createPackageConfigBuilder("/namespace");
this.conventionsService = new ConventionsServiceImpl("/WEB-INF/location");
DefaultResultMapBuilder builder = new DefaultResultMapBuilder(context, container, "dispatcher,velocity,freemarker");
Map<String, ResultConfig> results = builder.build(InheritedResultExtends.class, null, "result-inheritance-extends", packageConfig);
assertEquals(1, results.size());
assertEquals("error", results.get("error").getName());
assertEquals(3, results.get("error").getParams().size());
assertEquals("org.apache.struts2.dispatcher.ServletDispatcherResult", results.get("error").getClassName());
assertEquals("/WEB-INF/location/namespace/error.jsp", results.get("error").getParams().get("location"));
assertEquals("value", results.get("error").getParams().get("key"));
assertEquals("value1", results.get("error").getParams().get("key1"));
EasyMock.verify(context);
}
public void testClassLevelOverwriteInheritedSingleResultAnnotation() throws Exception {
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
// Setup some mock jsps
Set<String> resources = new HashSet<String>();
EasyMock.expect(context.getResourcePaths("/WEB-INF/location/namespace/")).andReturn(resources);
EasyMock.replay(context);
PackageConfig packageConfig = createPackageConfigBuilder("/namespace");
this.conventionsService = new ConventionsServiceImpl("/WEB-INF/location");
DefaultResultMapBuilder builder = new DefaultResultMapBuilder(context, container, "dispatcher,velocity,freemarker");
Map<String, ResultConfig> results = builder.build(OverrideInheritedResultExtends.class, null, "result-inheritance-extends", packageConfig);
assertEquals(1, results.size());
assertEquals("error", results.get("error").getName());
assertEquals(5, results.get("error").getParams().size());
assertEquals("org.apache.struts2.dispatcher.ServletDispatcherResult", results.get("error").getClassName());
assertEquals("/WEB-INF/location/namespace/error.jsp", results.get("error").getParams().get("location"));
assertEquals("value", results.get("error").getParams().get("key"));
assertEquals("value1", results.get("error").getParams().get("key1"));
assertEquals("value-overwritten", results.get("error").getParams().get("key-overwritten"));
assertEquals("value1-overwritten", results.get("error").getParams().get("key1-overwritten"));
EasyMock.verify(context);
}
public void testClassLevelMultipleResultAnnotation() throws Exception {
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
@@ -192,6 +243,45 @@ public class DefaultResultMapBuilderTest extends TestCase {
EasyMock.verify(context);
}
public void testClassLevelInheritanceMultipleResultAnnotation() throws Exception {
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
// Setup some mock jsps
Set<String> resources = new HashSet<String>();
EasyMock.expect(context.getResourcePaths("/WEB-INF/location/namespace/")).andReturn(resources);
EasyMock.replay(context);
PackageConfig packageConfig = createPackageConfigBuilder("/namespace");
this.conventionsService = new ConventionsServiceImpl("/WEB-INF/location");
DefaultResultMapBuilder builder = new DefaultResultMapBuilder(context, container, "dispatcher,velocity,freemarker");
Map<String, ResultConfig> results = builder.build(InheritedResultsExtends.class, null, "class-level-results", packageConfig);
assertEquals(4, results.size());
assertEquals("error", results.get("error").getName());
assertEquals("input", results.get("input").getName());
assertEquals("success", results.get("success").getName());
assertEquals("failure", results.get("failure").getName());
assertEquals(3, results.get("error").getParams().size());
assertEquals("org.apache.struts2.dispatcher.ServletDispatcherResult", results.get("error").getClassName());
assertEquals("/WEB-INF/location/namespace/error.jsp", results.get("error").getParams().get("location"));
assertEquals("ann-value", results.get("error").getParams().get("key"));
assertEquals("ann-value1", results.get("error").getParams().get("key1"));
assertEquals(1, results.get("input").getParams().size());
assertEquals("foo.action", results.get("input").getParams().get("actionName"));
assertEquals("org.apache.struts2.dispatcher.ServletActionRedirectResult", results.get("input").getClassName());
assertEquals(3, results.get("failure").getParams().size());
assertEquals("/WEB-INF/location/namespace/action-failure.jsp", results.get("failure").getParams().get("location"));
assertEquals("org.apache.struts2.dispatcher.ServletDispatcherResult", results.get("failure").getClassName());
assertEquals("value", results.get("failure").getParams().get("key"));
assertEquals("value1", results.get("failure").getParams().get("key1"));
assertEquals(3, results.get("success").getParams().size());
assertEquals("/WEB-INF/location/namespace/action-success.jsp", results.get("success").getParams().get("location"));
assertEquals("org.apache.struts2.dispatcher.ServletDispatcherResult", results.get("success").getClassName());
assertEquals("value", results.get("success").getParams().get("key"));
assertEquals("value1", results.get("success").getParams().get("key1"));
EasyMock.verify(context);
}
public void testActionLevelSingleResultAnnotation() throws Exception {
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
@@ -254,9 +344,9 @@ public class DefaultResultMapBuilderTest extends TestCase {
ServletContext context = EasyMock.createNiceMock(ServletContext.class);
ResultTypeConfig resultType = new ResultTypeConfig.Builder("freemarker", "org.apache.struts2.dispatcher.ServletDispatcherResult").
defaultResultParam("location").build();
defaultResultParam("location").build();
PackageConfig packageConfig = new PackageConfig.Builder("package").
defaultResultType("dispatcher").addResultTypeConfig(resultType).build();
defaultResultType("dispatcher").addResultTypeConfig(resultType).build();
this.conventionsService = new ConventionsServiceImpl("/WEB-INF/component");
DefaultResultMapBuilder builder = new DefaultResultMapBuilder(context, container, "dispatcher,velocity,freemarker");
@@ -278,20 +368,20 @@ public class DefaultResultMapBuilderTest extends TestCase {
private PackageConfig createPackageConfigBuilder(String namespace) {
ResultTypeConfig resultType = new ResultTypeConfig.Builder("dispatcher", "org.apache.struts2.dispatcher.ServletDispatcherResult").
addParam("key", "value").addParam("key1", "value1").defaultResultParam("location").build();
addParam("key", "value").addParam("key1", "value1").defaultResultParam("location").build();
ResultTypeConfig redirect = new ResultTypeConfig.Builder("redirectAction",
"org.apache.struts2.dispatcher.ServletActionRedirectResult").defaultResultParam("actionName").build();
ResultTypeConfig redirect = new ResultTypeConfig.Builder("redirectAction",
"org.apache.struts2.dispatcher.ServletActionRedirectResult").defaultResultParam("actionName").build();
ResultTypeConfig ftlResultType = new ResultTypeConfig.Builder("freemarker",
"org.apache.struts2.views.freemarker.FreemarkerResult").defaultResultParam("location").build();
"org.apache.struts2.views.freemarker.FreemarkerResult").defaultResultParam("location").build();
return new PackageConfig.Builder("package").
namespace(namespace).
defaultResultType("dispatcher").
addResultTypeConfig(resultType).
addResultTypeConfig(redirect).
addResultTypeConfig(ftlResultType).build();
namespace(namespace).
defaultResultType("dispatcher").
addResultTypeConfig(resultType).
addResultTypeConfig(redirect).
addResultTypeConfig(ftlResultType).build();
}
private ServletContext mockServletContext(String resultPath) {
@@ -308,7 +398,7 @@ public class DefaultResultMapBuilderTest extends TestCase {
}
private void verify(ServletContext context, String resultPath, Map<String, ResultConfig> results,
boolean redirect) {
boolean redirect) {
assertEquals(4, results.size());
assertEquals("success", results.get("success").getName());
assertEquals("input", results.get("input").getName());
@@ -28,7 +28,6 @@ import static org.easymock.EasyMock.verify;
import java.util.*;
import java.net.MalformedURLException;
import java.lang.reflect.Method;
import junit.framework.TestCase;
@@ -61,6 +60,7 @@ import org.apache.struts2.convention.actions.result.ActionLevelResultAction;
import org.apache.struts2.convention.actions.result.ActionLevelResultsAction;
import org.apache.struts2.convention.actions.result.ClassLevelResultAction;
import org.apache.struts2.convention.actions.result.ClassLevelResultsAction;
import org.apache.struts2.convention.actions.result.InheritedResultExtends;
import org.apache.struts2.convention.actions.resultpath.ClassLevelResultPathAction;
import org.apache.struts2.convention.actions.resultpath.PackageLevelResultPathAction;
import org.apache.struts2.convention.actions.skip.Index;
@@ -87,7 +87,6 @@ import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Scope.Strategy;
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
import com.opensymphony.xwork2.ognl.OgnlUtil;
import javax.servlet.ServletContext;
@@ -241,6 +240,7 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
expect(resultMapBuilder.build(ClassLevelResultsAction.class, null, "class-level-results", resultPkg)).andReturn(results);
expect(resultMapBuilder.build(ActionLevelResultAction.class, getAnnotation(ActionLevelResultAction.class, "execute", Action.class), "action-level-result", resultPkg)).andReturn(results);
expect(resultMapBuilder.build(ActionLevelResultsAction.class, getAnnotation(ActionLevelResultsAction.class, "execute", Action.class), "action-level-results", resultPkg)).andReturn(results);
expect(resultMapBuilder.build(InheritedResultExtends.class, null, "inherited-result-extends", resultPkg)).andReturn(results);
/* org.apache.struts2.convention.actions.resultpath */
expect(resultMapBuilder.build(ClassLevelResultPathAction.class, null, "class-level-result-path", resultPathPkg)).andReturn(results);
@@ -449,12 +449,13 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
/* org.apache.struts2.convention.actions.result */
pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.result#struts-default#/result");
assertNotNull(pkgConfig);
assertEquals(4, pkgConfig.getActionConfigs().size());
assertEquals(5, pkgConfig.getActionConfigs().size());
verifyActionConfig(pkgConfig, "class-level-result", ClassLevelResultAction.class, "execute", pkgConfig.getName());
verifyActionConfig(pkgConfig, "class-level-results", ClassLevelResultsAction.class, "execute", pkgConfig.getName());
verifyActionConfig(pkgConfig, "action-level-result", ActionLevelResultAction.class, "execute", pkgConfig.getName());
verifyActionConfig(pkgConfig, "action-level-results", ActionLevelResultsAction.class, "execute", pkgConfig.getName());
verifyActionConfig(pkgConfig, "inherited-result-extends", InheritedResultExtends.class, "execute", pkgConfig.getName());
/* org.apache.struts2.convention.actions.resultpath */
pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.resultpath#struts-default#/resultpath");
assertNotNull(pkgConfig);
@@ -0,0 +1,25 @@
/*
* $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.struts2.convention.actions.result;
public class InheritedResultExtends extends InheritedResultTestBase {
}
@@ -0,0 +1,29 @@
/*
* $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.struts2.convention.actions.result;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Result;
@Result(name="error", location="error.jsp", params={"key", "value", "key1", "value1"})
public abstract class InheritedResultTestBase extends ActionSupport {
}
@@ -0,0 +1,24 @@
/*
* $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.struts2.convention.actions.result;
public class InheritedResultsExtends extends InheritedResultsTestBase{
}
@@ -0,0 +1,33 @@
/*
* $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.struts2.convention.actions.result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.convention.annotation.Result;
@Results({
@Result(name="error", location="error.jsp", params={"key", "ann-value", "key1", "ann-value1"}),
@Result(name="input", location="foo.action", type="redirectAction"),
@Result(name="success", location="/WEB-INF/location/namespace/action-success.jsp"),
@Result(name="failure", location="/WEB-INF/location/namespace/action-failure.jsp")
})
public abstract class InheritedResultsTestBase {
}
@@ -0,0 +1,27 @@
/*
* $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.struts2.convention.actions.result;
import org.apache.struts2.convention.annotation.Result;
@Result(name="error", location="error.jsp", params={"key-overwritten", "value-overwritten", "key1-overwritten", "value1-overwritten"})
public class OverrideInheritedResultExtends extends OverrideInheritedResultTestBase {
}
@@ -0,0 +1,27 @@
/*
* $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.struts2.convention.actions.result;
import org.apache.struts2.convention.annotation.Result;
@Result(name="error", location="error.jsp", params={"key", "value", "key1", "value1"})
public abstract class OverrideInheritedResultTestBase {
}