Author: mrdon Date: Sat Oct 13 08:41:39 2007 New Revision: 584413 URL: http://svn.apache.org/viewvc?rev=584413&view=rev Log: Adding action annotation WW-2251
Added: struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Action.java struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/AnnotatedAction.java Modified: struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java Added: struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Action.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Action.java?rev=584413&view=auto ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Action.java (added) +++ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/Action.java Sat Oct 13 08:41:39 2007 @@ -0,0 +1,31 @@ +/* + * $Id: Namespace.java 584166 2007-10-12 14:07:52Z mrdon $ + * + * 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.config; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + [EMAIL PROTECTED](RetentionPolicy.RUNTIME) +public @interface Action { + public static final String DEFAULT_NAMESPACE = "__default_namespace__"; + String namespace() default DEFAULT_NAMESPACE; + String name(); +} Modified: struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java?rev=584413&r1=584412&r2=584413&view=diff ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java (original) +++ struts/struts2/trunk/plugins/codebehind/src/main/java/org/apache/struts2/config/ClasspathPackageProvider.java Sat Oct 13 08:41:39 2007 @@ -246,7 +246,8 @@ public boolean matches(Class type) { // TODO: should also find annotated classes return (Action.class.isAssignableFrom(type) || - type.getSimpleName().endsWith("Action")); + type.getSimpleName().endsWith("Action") || + type.getAnnotation(org.apache.struts2.config.Action.class) != null); } }, pkgs); @@ -274,26 +275,53 @@ * @param cls Action or POJO instance to process * @param pkgs List of packages that were scanned for Actions */ - protected void processActionClass(Class cls, String[] pkgs) { + protected void processActionClass(Class<?> cls, String[] pkgs) { + ActionConfig actionConfig = new ActionConfig(); String name = cls.getName(); String actionPackage = cls.getPackage().getName(); String actionNamespace = null; String actionName = null; - for (String pkg : pkgs) { - if (name.startsWith(pkg)) { - if (LOG.isDebugEnabled()) { - LOG.debug("ClasspathPackageProvider: Processing class "+name); - } - name = name.substring(pkg.length() + 1); - + + org.apache.struts2.config.Action actionAnn = + (org.apache.struts2.config.Action) cls.getAnnotation(org.apache.struts2.config.Action.class); + if (actionAnn != null) { + actionName = actionAnn.name(); + if (actionAnn.namespace().equals(org.apache.struts2.config.Action.DEFAULT_NAMESPACE)) { actionNamespace = ""; - actionName = name; - int pos = name.lastIndexOf('.'); - if (pos > -1) { - actionNamespace = "/" + name.substring(0, pos).replace('.','/'); - actionName = name.substring(pos+1); + } else { + actionNamespace = actionAnn.namespace(); + } + } else { + for (String pkg : pkgs) { + if (name.startsWith(pkg)) { + if (LOG.isDebugEnabled()) { + LOG.debug("ClasspathPackageProvider: Processing class "+name); + } + name = name.substring(pkg.length() + 1); + + actionNamespace = ""; + actionName = name; + int pos = name.lastIndexOf('.'); + if (pos > -1) { + actionNamespace = "/" + name.substring(0, pos).replace('.','/'); + actionName = name.substring(pos+1); + } + break; } - break; + } + // Truncate Action suffix if found + if (actionName.endsWith(ACTION)) { + actionName = actionName.substring(0, actionName.length() - ACTION.length()); + } + + // Force initial letter of action to lowercase, if desired + if ((forceLowerCase) && (actionName.length() > 1)) { + int lowerPos = actionName.lastIndexOf('/') + 1; + StringBuilder sb = new StringBuilder(); + sb.append(actionName.substring(0, lowerPos)); + sb.append(Character.toLowerCase(actionName.charAt(lowerPos))); + sb.append(actionName.substring(lowerPos + 1)); + actionName = sb.toString(); } } @@ -318,22 +346,6 @@ } } - // Truncate Action suffix if found - if (actionName.endsWith(ACTION)) { - actionName = actionName.substring(0, actionName.length() - ACTION.length()); - } - - // Force initial letter of action to lowercase, if desired - if ((forceLowerCase) && (actionName.length() > 1)) { - int lowerPos = actionName.lastIndexOf('/') + 1; - StringBuilder sb = new StringBuilder(); - sb.append(actionName.substring(0, lowerPos)); - sb.append(Character.toLowerCase(actionName.charAt(lowerPos))); - sb.append(actionName.substring(lowerPos + 1)); - actionName = sb.toString(); - } - - ActionConfig actionConfig = new ActionConfig(); actionConfig.setClassName(cls.getName()); actionConfig.setPackageName(actionPackage); @@ -355,15 +367,27 @@ protected PackageConfig loadPackageConfig(String actionNamespace, String actionPackage, Class actionClass) { PackageConfig parent = null; + // Check for the @Namespace annotation if (actionClass != null) { Namespace ns = (Namespace) actionClass.getAnnotation(Namespace.class); if (ns != null) { parent = loadPackageConfig(actionNamespace, actionPackage, null); actionNamespace = ns.value(); actionPackage = actionClass.getName(); + + // See if the namespace has been overridden by the @Action annotation + } else { + org.apache.struts2.config.Action actionAnn = + (org.apache.struts2.config.Action) actionClass.getAnnotation(org.apache.struts2.config.Action.class); + if (actionAnn != null && !actionAnn.DEFAULT_NAMESPACE.equals(actionAnn.namespace())) { + // we pass null as the namespace in case the parent package hasn't been loaded yet + parent = loadPackageConfig(null, actionPackage, null); + actionPackage = actionClass.getName(); + } } } + PackageConfig pkgConfig = loadedPackageConfigs.get(actionPackage); if (pkgConfig == null) { pkgConfig = new PackageConfig(); @@ -382,6 +406,10 @@ pkgConfig.setNamespace(actionNamespace); loadedPackageConfigs.put(actionPackage, pkgConfig); + + // if the parent package was first created by a child, ensure the namespace is correct + } else if (pkgConfig.getNamespace() == null) { + pkgConfig.setNamespace(actionNamespace); } return pkgConfig; } Added: struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/AnnotatedAction.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/AnnotatedAction.java?rev=584413&view=auto ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/AnnotatedAction.java (added) +++ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/AnnotatedAction.java Sat Oct 13 08:41:39 2007 @@ -0,0 +1,26 @@ +/* + * $Id: CustomNamespaceAction.java 584166 2007-10-12 14:07:52Z mrdon $ + * + * 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.config; + [EMAIL PROTECTED](name="myaction",namespace="/foo") +public class AnnotatedAction { + +} Modified: struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java?rev=584413&r1=584412&r2=584413&view=diff ============================================================================== --- struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java (original) +++ struts/struts2/trunk/plugins/codebehind/src/test/java/org/apache/struts2/config/ClasspathPackageProviderTest.java Sat Oct 13 08:41:39 2007 @@ -20,9 +20,11 @@ */ package org.apache.struts2.config; +import java.util.HashMap; import java.util.Map; import org.apache.struts2.dispatcher.ServletDispatcherResult; +import org.apache.struts2.util.StrutsTestCaseHelper; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.entities.ActionConfig; @@ -38,7 +40,7 @@ ClasspathPackageProvider provider; Configuration config; - public void setUp() { + public void setUp() throws Exception { provider = new ClasspathPackageProvider(); provider.setActionPackages("org.apache.struts2.config"); config = new DefaultConfiguration(); @@ -52,9 +54,14 @@ provider.init(config); provider.loadPackages(); } - + + public void tearDown() throws Exception { + provider = null; + config = null; + } + public void testFoundRootPackages() { - assertEquals(5, config.getPackageConfigs().size()); + assertEquals(6, config.getPackageConfigs().size()); PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config"); assertNotNull(pkg); Map configs = pkg.getActionConfigs(); @@ -85,7 +92,23 @@ ActionConfig ac = (ActionConfig) configs.get("customParentPackage"); assertNotNull(ac); } - + + public void testCustomActionAnnotation() { + PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config.AnnotatedAction"); + Map configs = pkg.getAllActionConfigs(); + // assertEquals(2, configs.size()); + ActionConfig config = (ActionConfig) configs.get("myaction"); + assertNotNull(config); + } + + public void testCustomActionAnnotationOfAnyName() { + PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config"); + Map configs = pkg.getAllActionConfigs(); + // assertEquals(2, configs.size()); + ActionConfig config = (ActionConfig) configs.get("myaction2"); + assertNotNull(config); + } + public void testResultAnnotations() { PackageConfig pkg = config.getPackageConfig("org.apache.struts2.config.cltest"); assertEquals("/cltest", pkg.getNamespace());