I am working on a Struts 2 application that is integrated with the Tiles plugin. It works fine on my local computer. But when I deploy it to a UNIX server and try to navigate past the login page to an action that uses Tiles, I get a CannotRenderException. I am using Tomcat v9.
Here is the relevant code:
Tiles.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="no.header.layout" template="/tiles/layout/noHeader.jsp">
<put-attribute name="title" value="System" />
<put-attribute name="includes" value="/tiles/global/includes.jsp" />
<put-attribute name="header" value="/tiles/global/header.jsp" />
<put-attribute name="body" value="/tiles/global/blank.jsp" />
<put-attribute name="footer" value="/tiles/global/footer.jsp" />
</definition>
<definition name="home.page" extends="no.header.layout"><!--THIS IS THE PAGE I'M TRYING TO LOAD-->
<put-attribute name="title" value="System Search"/>
<put-attribute name="body" value="/tiles/pages/home.jsp"/>
</definition>
</tiles-definitions>
Struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
"struts-6.0.dtd">
<struts>
<include file="struts-default.xml" />
<constant name="struts.devMode" value="false" />
<package name="default" extends="struts-default" namespace="/">
<result-types>
<result-type name = "tiles"
class="org.apache.struts2.views.tiles.TilesResult" />
</result-types>
<action name="home"> <!-- HERE IS THE ACTION I'M TRYING TO GET TO -->
<result type="tiles">home.page</result>
</action>
<action name="login" class="bcs.actions.LoginAction">
<result name="success" type="chain">home</result>
<result name="failure">/login.jsp?message=LOGIN_FAILURE</result>
<result name="failure2">/login.jsp?message=BC_LOGIN_FAILURE</result>
</action>
</package>
</struts>
noHeader.jsp
<%@ taglib uri = "http://tiles.apache.org/tags-tiles" prefix = "tiles"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/WEB-INF/struts-tags.tld" prefix="s" %>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=11">
<title><tiles:getAsString name='title' /></title>
<tiles:insertAttribute name='includes' flush='false' />
</head>
<body>
<div class='container'>
<div class='header_container'>
<tiles:insertAttribute name='header' flush='false' />
</div>
<div class='noheader_container'>
<tiles:insertAttribute name='body' flush='false' />
</div>
<div class='footer_container'>
<tiles:insertAttribute name='footer' flush='false' />
</div>
</div>
</body>
</html>
Here are the dependencies I'm using:
antlr-2.7.2.jar
bsf-2.3.0.jar
commons-beanutils-1.8.0.jar
commons-chain-1.2.jar
commons-codec-1.14.jar
commons-collections.jar
commons-dbutils-1.1.jar
commons-digester-2.0.jar
commons-fileupload-1.5.jar
commons-io-2.11.0.jar
commons-lang3-3.12.0.jar
commons-logging-1.0.4.jar
commons-text-1.10.0.jar
commons-validator-1.3.1.jar
el-api-1.0.jar
encoder-1.2.3.jar
files.txt
freemarker-2.3.32.jar
httpclient-4.5.12.jar
httpcore-4.4.13.jar
iText-2.1.7.jar
javassist-3.29.0-GA.jar
javax.el-3.0.1-b12.jar
jcl-over-slf4j-1.7.6.jar
json-simple-1.1.1.jar
jsp-api-2.1.jar
jstl-1.0.2.jar
log4j-1.2.15.jar
log4j-api-2.20.0.jar
log4j-core-2.20.0.jar
ognl-3.3.4.jar
ojdbc6.jar
oro-2.0.8.jar
poi-3.2-FINAL-20081019.jar
poi-contrib-3.2-FINAL-20081019.jar
poi-scratchpad-3.2-FINAL-20081019.jar
servlet-api-2.5.jar
slf4j-api-2.0.7.jar
standard-1.0.6.jar
struts-el-1.3.10.jar
struts-extras-1.3.10.jar
struts-faces-1.3.10.jar
struts-mailreader-dao-1.3.10.jar
struts-scripting-1.3.10.jar
struts-taglib-1.3.10.jar
struts2-config-browser-plugin-6.2.0.jar
struts2-core-6.2.0.jar
struts2-tiles-plugin-6.2.0.jar
tiles-api-3.0.8.jar
tiles-autotag-core-runtime-1.2.jar
tiles-compat-3.0.8.jar
tiles-core-3.0.8.jar
tiles-el-3.0.8.jar
tiles-freemarker-3.0.8.jar
tiles-jsp-3.0.8.jar
tiles-ognl-3.0.8.jar
tiles-request-api-1.0.7.jar
tiles-request-freemarker-1.0.7.jar
tiles-request-jsp-1.0.7.jar
tiles-request-servlet-1.0.7.jar
tiles-servlet-3.0.8.jar
tiles-template-3.0.8.jar
xercesImpl-2.12.2.jar
xwork-2.1.2.jar
And here is the exception:
ERROR org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler - Exception occurred during processing request: Cannot render an attribute that is not a string, toString returns: null
org.apache.tiles.request.render.CannotRenderException: Cannot render an attribute that is not a string, toString returns: null
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:255) ~[tiles-core-3.0.8.jar:3.0.8]
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:397) ~[tiles-core-3.0.8.jar:3.0.8]
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:238) ~[tiles-core-3.0.8.jar:3.0.8]
at org.apache.tiles.TilesContainerWrapper.render(TilesContainerWrapper.java:103) ~[tiles-api-3.0.8.jar:3.0.8]
at org.apache.tiles.impl.mgmt.CachingTilesContainer.render(CachingTilesContainer.java:126) ~[tiles-core-3.0.8.jar:3.0.8]
at org.apache.struts2.views.tiles.TilesResult.doExecute(TilesResult.java:158) ~[struts2-tiles-plugin-6.2.0.jar:6.2.0]
at org.apache.struts2.result.StrutsResultSupport.execute(StrutsResultSupport.java:206) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:377) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:284) ~[struts2-core-6.2.0.jar:6.2.0]
at bcs.actions.SessionPreProcessor.intercept(SessionPreProcessor.java:53) ~[classes/:?]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:256) ~[struts2-core-6.2.0.jar:6.2.0]
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:179) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:263) ~[struts2-core-6.2.0.jar:6.2.0]
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:49) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at org.apache.struts2.interceptor.FetchMetadataInterceptor.intercept(FetchMetadataInterceptor.java:78) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at org.apache.struts2.interceptor.CoopInterceptor.intercept(CoopInterceptor.java:57) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at org.apache.struts2.interceptor.CoepInterceptor.intercept(CoepInterceptor.java:55) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.doIntercept(ConversionErrorInterceptor.java:143) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:152) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.executeConditional(DefaultActionInvocation.java:299) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:152) ~[struts2-core-6.2.0.jar:6.2.0]
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:99) ~[struts2-core-6.2.0.jar:6.2.0]
I have tried commenting out attributes in both tiles.xml and noHeader.jsp, omitting a custom interceptor that I have, using different tiles-config dtd files, and checking the spelling of the templates and values. I have also made sure the app server has the necessary permissions. Other than that, I'm not sure what else to try.
There was an old tiles-defs.xml file left over from when the project was using Struts 1.3 instead of 2. Once I deleted that file and the associated tiles-config_1_3.dtd, the issue went away. Although I'm curious as to why the old xml file would affect the Struts 2 code.