Upgrading to Struts 1.3
Struts 1.3 is intended to be backwards compatible with Struts 1.2.x; however, it will not be a 100% drop-in replacement. Here are things to note when you are upgrading to Struts 1.3
1. Move to Servlet 2.3/JSP 1.2 baseline
Beginning with Struts 1.3, a servlet container that supports Servlet 2.3 and JSP 1.2 (such as Tomcat 4.x) is required.
2. Packaging
While previously Struts was distributed as a "monolithic" jar, beginning with the 1.3.0 release, many things which were formerly in the "core" have been split out into their own distributions. You will always need "struts-core-1.3.x.jar", and you may need one or more of the following:
struts-taglib-1.3.x.jar
(if you want to use the JSP tag libraries, except for the Tiles tag library)struts-el-1.3.x.jar
(in addition to struts-taglib) if you want to use the JSTL expression languagestruts-tiles-1.3.x.jar
(if you want to use Tiles)struts-extras-1.3x.jar
(if you useDispachAction
for example)
Additional note on using tiles : I migrated to Struts 1.3.5 and forgot to upgrade struts-tiles.tld
in my WEB-INF
-directory. If you store it there as well (usefull for some IDE's, no doubt there is a better way ..., extract the correct version from struts-tiles-1.3.x.jar
.
3. Dependencies
A number of dependencies have changed from Struts 1.2.x
3.1 Chain 1.0
Struts 1.3 introduces a new dependency on Commons Chain version 1.0. - remember to deploy the Chain jar
N.B. Struts 1.3.5 was released with a dependency on Chain 1.0 - however Chain 1.1 is now available for download with a number of bug fixes
3.2 File Upload 1.1.1
Struts 1.3 has an optional dependency on Commons FileUpload version 1.1.1 (previously was version 1.0). As well as needing to upgrade the FileUpload jar you will now also need the Commons IO Version 1.1 jar.
3.3 Commons Validator 1.3.0
Struts 1.3 now depends on Commons Validator version 1.3.0 (previous was version 1.1.4) - remember to upgrade the Validator jar.
- Validator 1.3.0 will recognize config files from prior versions. Optionally, you may
- Change the doctype declaration at the top of validation.xml to refer to the dtd for version 1.3.0
<!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_3_0.dtd">
- If you change the doctype you will have to change the deprecated arg0-arg3 elements to arg elements.
- The main improvements between Validator 1.1.4 and Validator 1.3.0 are described here
- You must upgrade to the new version of validator-rules.xml. This file is included in struts-core-1.3.x.jar, so the easiest way to upgrade is to delete any copies you may have in your application and use the following Validator Plugin configuration:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/org/apache/struts/validator/validator-rules.xml, /WEB-INF/validation.xml"/> </plug-in>
4. Configuration
4.1 CoR Request Processor
The default Request Processor for Struts 1.3 is the new Chain (CoR) based ComposableRequestProcessor.
By default, the ComposableRequestProcessor will use a configuration file included in the struts-core JAR, and you won't need to do anything.
4.2 Original Request Processors
If you want to continue using either of the existing Request Processors (i.e. RequestProcessor or TilesRequestProcessor) then you need to specify this in the controller element of the struts-config.xml
<controller processorClass="org.apache.struts.action.RequestProcessor" />
<controller processorClass="org.apache.struts.tiles.TilesRequestProcessor" />
NOTE You should only do this if you specifically know you need to use one of these request processors. If you're not sure, do not set this. If you want to use Tiles, there is a different way to specify this in Struts 1.3.x which does not require changing the processorClass (see the next section) Also note that if you have specified any other processorClass and you continue to use it, you will not be able to take advantage of certain new features which are only implemented as chain commands (e.g. per-action-mapping command execution). You are encouraged to adapt the logic in your custom RequestProcessor into chain commands and configure those commands in a custom chain-config.xml
4.3 Tiles
If you want to use Tiles, you must instruct Struts to use a configuration file included in the struts-tiles JAR instead. To do this:
- Add a chainConfig init-param in the web.xml pointing to the location of the chain-config.xml
<init-param> <param-name>chainConfig</param-name> <param-value>org/apache/struts/tiles/chain-config.xml</param-value> </init-param>
N.B. The tiles chain-config.xml
included with Struts 1.3.5 has two commands missing from the configuration (see Issue #STR-2935) - this can be rectified by downloading this version of the tiles chain-config.xml
In addition to configuring the ComposableRequestProcessor to use the provided Tiles chain config file, you should also update the DOCTYPE definition in your tiles-defs.xml file:
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 1.3//EN" "http://struts.apache.org/dtds/tiles-config_1_3.dtd">
You can do much more to configure the ComposableRequestProcessor, but those details are outside the scope of this document.
4.4 Struts Config File DTD
Change the doctype declaration at the top of your struts config files to refer to the dtd for version 1.3.0:
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">
5 Deprecations which have been removed
5.1 struts-config_1_3.dtd
View differences between the 1.2 and 1.3 DTDs here.
- Removed the contextRelative attribute of the <forward> element.
- Removed the dynamic attribute of the <form> element
- Removed the <data-sources> and <data-source> elements
5.2 Classes
- ActionError has been removed. Use ActionMessage instead.
- DataSourceConfig has been removed.
5.3 Methods and properties
Class |
Member |
Comments |
||
Action |
defaultLocale |
Use Locale.getDefault directly. |
||
Action |
getDataSource(request), getDataSource(request,key) |
FIXME |
||
Action |
saveErrors(HttpServletRequest request, ActionErrors errors) |
Use saveErrors(HttpServletRequest, ActionMessages) instead. |
||
ActionErrors |
GLOBAL_ERROR |
Use ActionMessages.GLOBAL_MESSAGE instead. |
||
ActionErrors |
add |
Use add(String, ActionMessage) instead. |
||
DynaActionFormClass |
clear() |
No longer need to Clear our cache of <code>DynaActionFormClass</code> instances. |
||
ExceptionHandler |
void storeException(...ActionError...) |
Use storeException(...ActionMessage...) instead. |
||
RequestProcessor |
log(String) |
Use Commons Logging Log class |
||
RequestProcessor |
log(String,Throwable) |
Use Commons Logging Log class |
||
FormBeanConfig |
setDynamic() |
This value is now computed automatically. |
||
ForwardConfig |
contextRelative |
Use module instead |
||
ForwardConfig |
ForwardConfig(...contextRelative...) constructor |
Use ForwardConfig(...module...) instead. |
||
ModuleException |
error |
Use message instead. |
||
ModuleException |
getError |
Use getActionMessage() instead. |
||
validator.Resources |
SERVLET_CONTEXT_KEY |
Use SERVLET_CONTEXT_PARAM |
||
validator.Resources |
HTTP_SERVLET_REQUEST_KEY |
Use HTTP_SERVLET_REQUEST_PARAM |
||
validator.Resources |
ACTION_ERRORS_KEY |
Use ACTION_MESSAGES_PARAM |
||
validator.Resources |
getLocale() |
Use RequestUtils.getUserLocale() instead. |
||
validator.Resources |
getActionError() |
Use getActionMessage() instead. |
||
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="4c6dd1ed-3917-42e4-8fef-e0cc99b57474"><ac:plain-text-body><![CDATA[ |
RequestUtils |
computeURL [3 forms] |
Use equivalent method in [TagUtils], however the parameters are not the same so work with it |
]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="dd2d892d-1200-48c9-b256-da875a1af71a"><ac:plain-text-body><![CDATA[ |
RequestUtils |
selectModule() [2 forms] |
Use equivalent method in [ModuleUtils]. |
]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="73c0a61c-5a51-49ce-b607-c5cf25604c43"><ac:plain-text-body><![CDATA[ |
RequestUtils |
getModuleName() [2 forms] |
Use equivalent method in [ModuleUtils]. |
]]></ac:plain-text-body></ac:structured-macro> |
RequestUtils |
getRequestModuleConfig() |
Use equivalent method in ModuleUtils. |
||
RequestUtils |
saveException |
Use equivalent method in TagUtils. |
||
RequestUtils |
getModuleConfig() |
Use equivalent method in ModuleUtils. |
||
RequestUtils |
getModulePrefixes() |
Use equivalent method in ModuleUtils. |
||
MessageTag |
defaultLocale |
unused, no replacements. |
||
BaseHandlerTag |
defaultLocale |
unused, no replacements. |
||
ErrorsTag |
defaultLocale |
unused, no replacements. |
||
JavascriptValidatorTag |
defaultLocale |
unused, no replacements. |
||
OptionTag |
defaultLocale |
unused, no replacements. |
||
ErrorsTag |
lineEnd |
unused, no replacements. |
||
HtmlTag |
getCurrentLocale() |
locale is no longer being used. |
||
ImgTag |
isContextRelativeSet() |
contextRelative is no longer being used. |
||
TagUtils (Taglib) |
getActionErrors() |
use getActionMessages() instead. |
||
TagUtils (Tiles) |
getProperty() |
Use PropertyUtils.getProperty() directly. |
||
ResponseUtils |
write |
Use TagUtils.write |
||
ResponseUtils |
writePrevious |
Use TagUtils.writePrevious |
5.4 TLD URIs
The struts-taglib and struts-tiles distributions no longer include TLDs which are configured with the old URIs under the jakarta.apache.org domain name. You must make the following changes:
Deprecated, now removed |
Replacement |
http://jakarta.apache.org/struts/tags-bean |
http://struts.apache.org/tags-bean |
http://jakarta.apache.org/struts/tags-html |
http://struts.apache.org/tags-html |
http://jakarta.apache.org/struts/tags-logic |
http://struts.apache.org/tags-logic |
http://jakarta.apache.org/struts/tags-nested |
http://struts.apache.org/tags-nested |
http://jakarta.apache.org/struts/tags-tiles |
http://struts.apache.org/tags-tiles |
5.5 Tag Attributes
Tag |
Attribute |
Comments |
bean:include |
name |
Use page instead. |
html:html |
locale |
Use lang instead. |
html:img |
contextRelative |
Use module instead. |
html:img |
lowsrc |
Non-standard attribute; No longer supported. |
5.6 Tag upgrading
If you have specified a styleId for the html:form tag, you will see the following error:
javax.servlet.jsp.JspException: Cannot specify "styleId" when in XHTML mode as the HTML "id" attribute is already used to store the bean name at org.apache.struts.taglib.html.FormTag.renderName(FormTag.java:570)
The solution is to remove the styleId and use the name of your form bean, as that will be inserted as the id in your HTML.
6. Deployment
- If you experience NoClassDefFoundErrors in JSP code after deploying a Struts 1.3 webapp using the same context name it had under a prior version, try deleting the generated .java and .class files related to the JSP files. In Tomcat, these are found under the $TOMCAT_HOME/work directory.
- In particular, the package name of the Tiles classes changed from org.apache.struts.taglib.tiles to org.apache.struts.tiles.taglib, so you may see: java.lang.NoClassDefFoundError: org.apache.struts.taglib.tiles.InsertTag
Some users who were not using the Struts taglibs or tiles have reported success with simply "dropping-in" the Struts 1.3 "core" JAR and Commons Chain 1.0. This is unlikely to work if you have not been keeping up with deprecation warnings, as many deprecated methods and classes have been completely removed with the Struts 1.3.0 release.
Note that even if you explicitly specify in the struts-config.xml that you want to use the original RequestProcessor rather than the ComposableRequestProcessor, you still must add Commons Chain to your webapp's classpath, as the chain initialization code currently lives in the ActionServlet. This architecture is open to discussion, but as it is currently, you need Commons Chain in your webapp even if you don't use the ComposableRequestProcessor.
(please add notes here as you gain experience with this migration)