Struts 2 upgrade

On this page

Still need help?

The Atlassian Community is here for you.

Ask the community

Confluence is working to upgrade from WebWork 2.1.x to Apache Struts 2 in Confluence 8.0.

We've been on WebWork 2.1.x for a long time while maintaining its open-source library. To modernise our code base, reduce tech debt and secure against OGNL attacks, we've decided to move to Struts 2.

This page contains a migration plan, breaking changes as well as some future improvements you can expect. We'll continue to share updates on this page as we progress with the Struts 2 upgrade.

How to test

You can test your plugin against our Struts development release and by removing XWork/WebWork in your dependencies. If your plugin uses confluence-plugins-platform-pom then it should get Struts 2 as managed dependency now.

Background on WebWork/Struts relationship

The WebWork framework spun off from Apache Struts 1 aiming to offer enhancements and refinements while retaining the same general architecture of the original Struts framework. In December 2005, it was announced that WebWork 2.2 was adopted as Apache Struts 2, which reached its first full release in February 2007.[1]

Overview of breaking changes

  • If your plugin has classes extending ActionSupport directly, we'd recommend extending ConfluenceActionSupport to get some compatibility support from Confluence, or if not possible, then move to com.opensymphony.xwork2.ActionSupport 

  • $webwork.htmlEncode will no longer be available in the Velocity context, $htmlUtil.htmlEncode will be used instead.

  • The AroundInterceptor has been removed. If your application extends the AroundInterceptor, you can either import the class into your source code from WebWork 2 (pursuant to the Open Symphony License) and modify it to server as your own base class, or rewrite your interceptor.

  • There are a few new package coordinates and class replacements that are breaking in nature listed in the table below.

Webwork2.xStruts2Comments
com.opensymphony.xwork.*com.opensymphony.xwork2.*
com.opensymphony.webwork.*org.apache.struts2.*
DispatcherUtilDispatcher
com.opensymphony.webwork.config.Configurationorg.apache.struts2.config.Settings
com.opensymphony.webwork.ServletActionContextorg.apache.struts2.ServletActionContext

Compatibility layer class:

com.atlassian.confluence.compat.struts2.actioncontext.ServletActionContextCompatManager

$req$requestFor velocity VM files only. For now, we have put $req for backward compatibility, we might clean this up by end of 8.0
$res$responseFor velocity VM files only. For now, we have put $res for backward compatibility, we might clean this up by end of 8.0

#bodytag( "Component" <parameters>)
#bodytag( "TextField" <parameters>)

#scomponent(<parameters>) #end

#stextfield(<parameters>)

Moved away from #tag and #bodytag directives to #s based new form of component directives. So all these directive tags have now been moved to Struts format. For details and examples, see 30 August update.

private String xHtml; 

//Old format

public void setXHtml(String value) { .... } 

private String xHtml; 

//New format does have the first letter of the property name in uppercase

public void setxHtml(String value) { .... } 

If your Struts action has a setter method for a property that starts with a lowercase letter followed by an uppercase letter, for example pRoperty, make sure it follows the new format set<pRoperty>

The convention of trying a "do" form of an action method is supported in WebWork.

<action name="..." method="submit">   ... </action> 

In WebWork:

  • step 1: try to execute submit method in the action will fail
  • step 2: try to execute doSubmit method in the action, if Step 1 is fail, will fail


The convention of trying a "do" form of an action method is NOT supported in Struts 2.

<action name="..." method="submit">   ... </action>

In Struts:

  • try to execute submit method in the action will fail

The convention of trying a "do" form of an action method is not supported in Struts 2.

The convention of calling the "default" method via "doDefault" is not supported in Struts 2.

Update from  

More details on compat-lib 1.5.0

As we mentioned in our last update, we were developing a compat-lib to handle plugin cross-compatibility for XWork/WebWork and Struts across Confluence 7.x and 8.x. We have now released 1.5.0 version of confluence-compat-lib.

We have identified two classes that are used the most, and provided the following compatibility layers for them.

We have listed the compatibility layer in the third column of this table. Scroll the table to see the compatibility layer class.

XWork/Webwork classStruts 2 classCompatibility layer class
com.opensymphony.webwork.ServletActionContextorg.apache.struts2.ServletActionContextcom.atlassian.confluence.compat.struts2.actioncontext.ServletActionContextCompatManager
com.opensymphony.xwork.ActionContextcom.opensymphony.xwork2.ActionContextcom.atlassian.confluence.compat.struts2.actioncontext.ActionContextCompatManager

How to keep a single version of a plugin compatible

If you only want to keep a single version of a plugin compatible across Confluence 7.x and 8.x, you will need to add the following dependency:

<dependency>
    <groupId>com.atlassian.confluence.compat</groupId>
    <artifactId>confluence-compat-lib</artifactId>
    <version>1.5.0</version>
</dependency>
  • For ServletActionContext, use ServletActionContextCompatManager
    • If you only want to use getRequest() , getResponse()  or getContext(), you can also use com.atlassian.core.filters.ServletContextThreadLocal as this class is available on both Confluence 7.x and 8.x already from Confluence core.
  • For ActionContext, use ActionContextCompatManager 

Use the below example code to replace ServletActionContext to make your plugin compatible across old and new versions of Confluence.

See an example
In spring-components.xml
<beans:bean id="servletActionContextCompat" class="com.atlassian.confluence.compat.struts2.ServletActionContextCompatManager"/>

//Wiring in a class 
public void setServletActionContextCompatManager(@Qualifier("servletActionContextCompat") ServletActionContextCompatManager servletActionContextCompatManager) {
        this.servletActionContextCompatManager = servletActionContextCompatManager;
}

//Usage in a class
public HttpServletRequest useActionContextForRequest() {
        return this.servletActionContextCompatManager.getRequest();
}

Add the following packages to the "import packages" section of amps-maven-plugin or confluence-maven-plugin in your pom.xml:

  • com.opensymphony.xwork;resolution:=optional,

  • com.opensymphony.webwork;resolution:=optional,

  • org.apache.struts2;resolution:=optional,

  • com.opensymphony.xwork2;resolution:=optional,

See an example
In pom.xml
<plugin>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>amps-maven-plugin</artifactId>
    <configuration>
        <instructions>
            <DynamicImport-Package>
                com.opensymphony.xwork;resolution:=optional,
                com.opensymphony.webwork;resolution:=optional,
                org.apache.struts2;resolution:="optional",
                com.opensymphony.xwork2;resolution:="optional"
            </DynamicImport-Package>
        </instructions>
    </configuration>
</plugin>


This is the current structure of the compat interfaces for replacement usages:

/**
 * Provides version-agnostic implementations for ServletActionContext methods.
 */
interface ServletActionContextCompat {
    void setRequest(HttpServletRequest request);

    HttpServletRequest getRequest();

    void setResponse(HttpServletResponse response);

    HttpServletResponse getResponse();

    void setServletConfig(ServletConfig config);

    ServletConfig getServletConfig();
}
/**
 * Provides version-agnostic implementations for ActionContext methods.
 */
interface ActionContextCompat {
    void setApplication(Map application);

    Map getApplication();

    void setContextMap(Map contextMap);

    Map getContextMap();

    void setConversionErrors(Map conversionErrors);

    Map getConversionErrors();

    void setLocale(Locale locale);

    Locale getLocale();

    void setName(String name);

    String getName();

    void setParameters(Map parameters);

    Map getParameters();

    void setSession(Map session);

    Map getSession();

    Object get(Object key);

    void put(Object key, Object value);
}


Update from  

Milestone 8.0.0-struts-m48

  • If your Struts action has a setter method for a property that starts with a lowercase letter followed by an uppercase letter, for example pRoperty, ensure it follows the new format like: set<pRoperty>
See an example
private String xHtml;

//Old format
public void setXHtml(String value) {
....
}

//New format does not have first letter of the property name in uppercase
public void setxHtml(String value) {
....
}
  • There is also a change in behaviour to "do" Methods:
doActionMethod 

The convention of trying a "do" form of an action method is not supported.

<action name="..." method="submit"> 2  ... 3</action>

In WebWork:

  • step 1: try to execute submit method in the action will fail

  • step 2: try to execute doSubmit method in the action, if Step 1 has failed, will fail

In Struts2:

  • try to execute submit method in the action will fail

default method Calling the "default" method via "doDefault" is not supported.

To learn more, see Key changes from WebWork2 for more details.

  • The following table tracks issues fixed in this milestone: 

    Key Summary T Created Updated Due Assignee Reporter P Status Resolution
    Loading...
    Refresh

Confluence compat lib 1.5.0 is coming

A compat lib to handle plugin cross-compatibility for the Struts 2 upgrade is currently in development. We are targeting next week for a release. The compat lib will only address the most widely used classes across our plugins. 

Update from  

Milestone 8.0.0-struts-m39

  • 404s on UPM-based plugin re-install has been fixed by wiring the enabled/disabled lifecycle.

  • The following table tracks issues fixed in this milestone:

Key Summary T Created Updated Due Assignee Reporter P Status Resolution
Loading...
Refresh


Update from  

Milestone 8.0.0-struts-m027

  • Moved away from #tag and #bodytag directives to #s based new form of component directives. So all these directive tags have now been moved to Struts format. We plan to remove support for #tag/#bodytag in the next few days. Two examples that show the changes needed are:

#tag/#bodytag

New #s based tag directive

#bodytag( "Component" "label='create.support.zip.include.tomcat'" "name='includeServerLogs'" "value=includeServerLogs" "theme='aui'" "template='onofflist.vm'")}} #param ("description" "$i18n.getText('create.support.zip.include.tomcat.desc')") #end

#scomponent("label='create.support.zip.include.tomcat'" "name='includeServerLogs'" "value=includeServerLogs" "theme='aui'" "template='onofflist.vm'" "description=$i18n.getText('create.support.zip.include.tomcat.desc')") #end

#bodytag( "TextField" "label='create.support.zip.logs.other.directory'" "name='serverLogsDirectory'" "value=serverLogsDirectory" "theme='aui'")
#param ("description" "$i18n.getText('create.support.zip.logs.other.directory.desc')")
#end

#stextfield("label='create.support.zip.logs.other.directory'" "name='serverLogsDirectory'" "value=serverLogsDirectory" "theme='aui'"
"description=$i18n.getText('create.support.zip.logs.other.directory.desc')")


Note that only Component type tags require #end closing tag.

  • OGNL static method calls in atlassian-plugin.xml action wiring or in a velocity file won't work anymore. You will need to wrap that in the corresponding action in a new method and provide just the String/Object needed by Velocity file.

    • For example:

<result name="success" type="redirectwithflash">${@com.atlassian.confluence.util.GeneralUtil@getPageUrl(page)}</result>

can be replaced with:

<result name="success" type="redirectwithflash">${pageUrl}</result>

where-in a new getPageURL is exposed from the action itself.

  • Editor and attachments are now working. Our tests show that we have >98% of Confluence features working with this milestone.

  • The following table tracks issues fixed in this milestone:

Key Summary T Created Updated Due Assignee Reporter P Status Resolution
Loading...
Refresh

Update from  

Milestone 8.0.0-struts-m021

  • Note that we are targeting Struts 2.5.x first, and may bring out the newest Struts version 6.0 (known as 2.6 in old Struts style) at a later date.
  • The following table tracks issues of the known broken areas, and we'll try to keep the new incoming ones public. Additionally, there may be some broken areas in Velocity Struts rendering integration not listed in the table.

Key Summary T Created Updated Due Assignee Reporter P Status Resolution
Loading...
Refresh


Last modified on Sep 30, 2022

Was this helpful?

Yes
No
Provide feedback about this article
Powered by Confluence and Scroll Viewport.