skip to Main Content

If you are maintaining code, you may find yourself in a situation where you need to upgrade your framework to the latest version. Zirous maintains code bases for multiple clients, and recently we found a need for one of them to upgrade code to Java 8. This client has multiple applications that we needed to consider and multiple frameworks. Due to this, we needed our infrastructure team to upgrade to a newer version of Weblogic server, and the development team needed to upgrade applications to Java 8, Spring 5.2.5, and Struts 2.5.22. Struts 2.5.22 is the most current version of the Struts 2 framework and was released on November 29, 2019. The Struts 2.5.22 migration will be detailed out for you in this blog post.

You may be wondering why you might want to upgrade a newer version of Struts if your current version is working. Depending on the age of your code, you might find that your current version is reaching end of life (EOL) and will no longer be supported. There may be newer enhancements to the framework that you want to take advantage of. Another consideration might be that there is a security vulnerability that was discovered in your version and you want to update to make sure that the vulnerability has been patched. Check out all the known Struts 2 security vulnerabilities here. Once you decide to upgrade, you will need to consider what your current version is. If it’s an older version like our client’s was (2.0.11), you may want to upgrade in steps to make testing a little easier and break things down. If you go this route and are on a pre-2.3 version, I would recommend upgrading to 2.3, and then following the official documentation to upgrade from 2.3 to 2.5 . We decided to go directly to 2.5 to avoid needing to test multiple times.

Make sure you consider the following when upgrading to Struts 2.5:

What Java version is needed?

Double check your Java version; you will need Java 7 or above.

Which jars or Maven dependencies need to be updated?

Struts 2 jars can be downloaded here. Make sure all the versions of struts match when you are updating. If you are making use of a struts2-spring plugin jar, make sure the version of that jar matches your Struts 2 jar. You can also check the version notes here to see an example of the maven dependency if you are using maven. Dependencies can also be found here which include:

  • Upgrading Jackson to the latest version
  • OGNL 3.1.22 (or upgrade to OGNL 3.1.26 and adapt to its new features)
  • Any struts libraries you have included other than the core
  • commons-beanutils 1.9.4
  • Jackson-databind 2.9.9.3

Another option is to go to a maven repository like this one and view any compile dependencies listed. These will indicate the version required and will indicate if it is optional or not.

Items no longer supported in Struts 2.5

The following items are no longer supported in Struts 2.5, so you will need to find a replacement if you are currently using them:

  • Dojo plugin
  • Codebehind plugin
  • JSF plugin
  • Struts1 plugin

Change the Document Type Definition (DTD) of the XML files

Update the DTD at the top of the struts.xml file to the following:

<!DOCTYPE struts PUBLIC
     “-//Apache Software Foundation//DTD Struts Configuration 2.5//EN”
     “http://struts.apache.org/dtds/struts-2.5.dtd“>

Change the filter in web.xml

Instead of using the filter-class of org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter, you should use org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter. As a result, your filter element should look like this

<filter>
     <filter-name>struts2</filter-name>
     <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

JSP related changes

Make the following changes to your JSP files:

  • Remove the id attribute on struts related tags and replace it with the var attribute (<s:iterator id=”myIterator” value=”myValues”> becomes <s:iterator var=”myIterator” value=”myValues”>). We did a simple file search in eclipse to find each instance of the tags and make sure the id tag was updated.
    • <s:action>
    • <s:append>
    • <s:bean>
    • <s:date>
    • <s:generator>
    • <s:iterator>
    • <s:merge>
    • <s:number>
    • <s:set>
    • <s:sort>
    • <s:subset>
    • <s:text>
    • <s:url>
  • Remove the s:div tag and replace it with the plain html div tag.
  • Rename the escape attribute to escapeHtml.
  • If you are using number literals with Freemarker and have a number value with no quotes around it for the value, you must convert that value to a string with a decimal (i.e. value=70 becomes value=”70.0”). If you don’t want the decimal, make sure you add quotes around your value.

Field names should not start with a lowercase letter followed by an uppercase letter

If you have a field name that starts with a single lowercase letter that is followed by an uppercase letter like:

     private String aValue;

Previous versions of Struts would be looking for getters and setters like:

     public String getAValue() {}
     public void setAValue() {}

You will need to do one of the following:

  1. Change the accessors (getters and setters) to getaValue() and setaValue(), OR
  2. Update any field names that start with a lowercase letter followed by an uppercase letter to something like private String avalue; and use the accessor methods getAvalue() and setAvalue(). This would be the preferred method to use.

Tiles related changes

In Struts 2.5, a tiles-plugin is provided that uses Tiles3. Tiles2 is no longer in use, and Tiles3 no longer requires the tiles3-plugin, just the tiles-plugin. Make sure the version of the struts2-tiles-plugin matches your struts version. You may need to update your DTD if you aren’t using Tiles3 yet.

You may need to upgrade from log4j to log4j2

The Struts 2.5 framework now uses log4j2 as the logging layer, so if you are currently using log4j, you should upgrade to log4j2. Apache provides migration documentation for upgrading from Log4j 1.x to Log4j 2 here. The jars necessary can be downloaded from Apache as well here. The main issues we needed to address while upgrading to log4j2, other than the jars, were updating our code to use LogManager.getLogger instead of Logger.getLogger and having a log4j2.xml file instead of a log4j.xml that had a different format. Examples of this can be found at the migration link given above.

Additional changes are needed for migrating from a pre-2.3 version

The following changes are required when upgrading from a pre-2.3 version of Struts:

  • Remove dynamic method invocation. Dynamic method invocation gives you the ability to access a method directly from a jsp by adding a ! onto the end of the action and then the method name. So, for example, if a login action has a public method getPassword that doesn’t require any arguments, someone could access that method by visiting the URL: http://myUrl/myApp/login!getPassword.action. To avoid a security risk, dynamic method invocation has been turned off by default for Struts 2.5. If you are currently using dynamic method invocation you will need to do one of the following:
    • If you use dynamic method invocation in multiple places and don’t find any you think would be cause for concern, or if your application resides in a protected area not available to the public, you may choose to turn dynamic method invocation back on. If you decide to go this route, you will need to make the following changes to struts.xml
      • Add <constant name=”struts.additional.excludedPatterns” value=”^(action|method):.*”/>
      • Add <constant name=”struts.enable.DynamicMethodInvocation” value=”true” />
      • For each package defined set strict-method-invocation=”false”
    • For every place you currently use dynamic method invocation, add a variable to the form (i.e. actionStr) which you set on the jsp before you submit the action to indicate which method the code should go to and handle those actionStr options in the execute method.
    • Separate out all the dynamic method invocation instances into separate actions.
  • Remove static method accesses.
  • Rename some interceptor-ref classes in struts.xml. We ran into the following:
    • servlet-config became servletConfig
    • static-params became staticParams
    • redirect-action became redirectAction
  • Change the imports on your Java classes for commons-lang3 and xwork-core, as there were some updates. The easiest way to do this is in Eclipse. When you are on the Java file, use Ctrl-Shift-O to organize imports, and these should be found for you.

Additional gotchas to look out for

While every project is different, we ran into these additional issues when performing our upgrade:

  • If you are using a struts2-spring plugin and you update your Spring version to the newest like we did (version 2.5.2 for us), be aware that the component scans defined in applicationContext.xml are performed recursively. Our older version did not work this way, so we had to remove some component scans. For example, you don’t need to do a base-package scan on both myproject.dao and myproject.dao.mysubfolder — only the first scan is needed. This was especially frustrating, because the scan worked fine while running the code locally, but when we deployed to the QA environment the deployment would fail.
  • If you run into issues during deployment, make sure you clear your cache, temp, and build directories to force a recompile of the jsp files to see if that solves the issue before attempting any further fixes.
  • If you run into a java.lang.ClassNotFoundException, try using a site like https://findjar.com/. You can search for classes, and it will tell you which jars contain that class. Then you can go to a maven repository and download the necessary jar to add to your classpath.
  • FindJAR.com can also be useful if you are running into jar collision errors to determine which jars may be causing the issue. If this is the case you may need to include jars from your server instead of having the jar in your WEB-INF/lib folder. Another possibility is to make changes to your weblogic.xml file and try setting prefer-web-inf classes to true. If you know the specific classes that cause issues, you can try setting prefer-application-packages or prefer-application-resources and listing the class path pattern you want to use from your project vs. the server. Prefer-application-resources ended up working for us while prefer-application-packages did not. We ended up needing to use the following:

     <wls:container-descriptor>
          <wls:prefer-application-resources>
               <wls:resource-name>javax.xml.*</wls:resource-name>
               <wls:resource-name>org.xml.*</wls:resource-name>
               <wls:resource-name>net.sf.cglib.*</wls:resource-name>
               <wls:resource-name>org.slf4j</wls:resource-name>
               <wls:resource-name>log4j</wls:resource-name>
          </wls:prefer-application-resources>
     </wls:container-descriptor>

Conclusion

As you can see, there are many considerations when migrating to Struts 2.5 from a previous release. Many times, an upgrade isn’t an option but is a requirement, especially if your previous version is coming up on its end of life or if there are known security issues that need to be addressed. If you are facing a need for a migration and this list seems intimidating to you or you would prefer to have some assistance from someone who has already been through the process, feel free to reach out to us at Zirous. We would be happy to discuss options with you and provide a helping hand!

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top