Re: File Upload Failure in Struts 7.0.3 Migration - UploadedFilesAware Implementation Issue

Zoran Avtarovski <[email protected]> Wed, 4 Jun 2025 11:13:46 +1000
Newsgroups gmane.comp.jakarta.struts.user
Message-ID <[email protected]>
Thanks for that.

It doesn't look like you have the same issue we did. I wish I could be 
of more help.

I can only suggest start with example app working and then implement 
your requirements on a step by step basis.

In the end that's what helped us identify the issue and get it working.

Z.




On 4/6/2025 4:56 am, Jesus Moreno wrote:
> Sure, my web.xml looks like this:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
>           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>           xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee 
> https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
>           version="6.0">
>      <display-name>Struts Blank</display-name>
>        <!-- 1. Context Parameter para Log4j2 -->
>      <context-param>
>          <param-name>log4jConfiguration</param-name>
>          <param-value>/WEB-INF/classes/log4j2.xml</param-value>
>      </context-param>
>      <filter>
>          <filter-name>struts2</filter-name>
>
> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
>      </filter>
>      <filter-mapping>
>          <filter-name>struts2</filter-name>
>          <url-pattern>/*</url-pattern>
>      </filter-mapping>
> </web-app>
>
> I forgot also show my struts.xml:
>
> <?xml version="1.0" encoding="UTF-8" ?>
> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts
> Configuration 6.0//EN"
>      "https://struts.apache.org/dtds/struts-6.0.dtd">
> <struts>
>       <constant name="struts.ui.theme" value="simple"/> <!-- En struts.xml
> -->
>       <constant name="struts.ui.templateDir" value="template"/>
>       <constant name="struts.ui.templateSuffix" value="ftl"/>
>       <constant name="struts.devMode" value="true"/>
>       <constant name="struts.enable.DynamicMethodInvocation" value="false"/>
>       <constant name="struts.logging.fileUploadInterceptor" value="TRACE"/>
>       <constant name="struts.logging.level" value="TRACE"/>
>       <constant name="struts.multipart.parser"
> value="mx.com.struts.action.DebugMultiPartRequest"/>  <!-- Using my custom
> DebugMultiPartRequest -->
>
>       <package name="default" extends="struts-default">
>
>        <action name="">
>     <result>/index.jsp</result>
> </action>
>
> <action name="hello" class="mx.com.struts.action.HelloAction">
>            <result name="success">/success.jsp</result>
>            <result name="error">/error.jsp</result>
>          </action>
>
>      </package>
>
> </struts>
>
> On the log I can see that I don't have file on my action:
>
> 2025-06-03 12:48:20 DEBUG ActionFileUploadInterceptor:200 - Found multipart
> request: MultiPartRequestWrapper
> 2025-06-03 12:48:20 DEBUG ActionFileUploadInterceptor:179 - No files have
> been uploaded/accepted
>
> Now I can see is blocked!. I was reading that this message is normal on the
> log:
>
> 2025-06-03 12:48:21 DEBUG DefaultAcceptedPatternsChecker:115 - Sets
> accepted patterns to
> [[\w+((\.\w+)|(\[\d+])|(\(\d+\))|(\['(\w-?|[\u4e00-\u9fa5]-?)+'])|(\('(\w-?|[\u4e00-\u9fa5]-?)+'\)))*]],
> note this impacts the safety of your application!
> 2025-06-03 12:48:21 DEBUG StrutsUrlEncoder:38 - Using default encoding:
> UTF-8
> 2025-06-03 12:48:21 DEBUG SecurityMemberAccess:142 - Checking access for
> [target: mx.com.struts.action.HelloAction@4489b4fa, member: private
> org.apache.struts2.dispatcher.multipart.UploadedFile
> mx.com.struts.action.HelloAction.miLogo, property: miLogo]
> 2025-06-03 12:48:21 WARN  SecurityMemberAccess:174 - Access to non-public
> [private org.apache.struts2.dispatcher.multipart.UploadedFile
> mx.com.struts.action.HelloAction.miLogo] is blocked!
> 2025-06-03 12:48:21 DEBUG InstantiatingNullHandler:106 - Entering
> nullPropertyValue [target=[mx.com.struts.action.HelloAction@4489b4fa,
> org.apache.struts2.text.DefaultTextProvider@287a1ff7], property=miLogo]
>
> As comment I changed file name as miLogo because I was trying use a
> different name like upload.
>
> Thanks for the support.
>
> JMC
>
>
> El lun, 2 jun 2025 a las 23:44, Zoran Avtarovski (<[email protected]>)
> escribió:
>
>> Hi Jesus,
>>
>> What does your web.xml look like with regards to the struts filters? We
>> had a similar issue which was resolved by moving to the combined
>> StrutsPrepareAndExecuteFilter. Sitemesh also played a part in our issue,
>> but I think by what you are seeing it's worth trying.
>>
>> Z.
>>
>> On 1/6/2025 6:29 am, Jesus Moreno wrote:
>>> Hi Lukasz, thanks for your appreciated comments.
>>>
>>> I would like to explain in more detail what we have done to try to find
>> the
>>> problem and solve it. Here the context:
>>>
>>> This is my environment:
>>>
>>> - Struts Version: 7.0.3
>>> - Java Version: 17
>>> - Servlet Container: Apache Tomcat 10.1.36
>>> - Key Dependencies (pom):
>>> - struts2-core:7.0.3
>>> - struts2-convention-plugin:7.0.3
>>> - struts2-json-plugin:7.0.3
>>> - jakarta.servlet-api:5.0.0
>>> - log4j-core:2.17.2
>>> - Enforced exclusions: javax.servlet:*, javax.activation:*
>>>
>>> We've created a basic Maven project (standard archetype) with a simple
>> file
>>> upload form containing:
>>>       - 4 regular text fields (working correctly with
>>> @StrutsParameter(depth=0))
>>>       - 1 file upload field (<input type="file" name="upload">)
>>>
>>> This is my basic jsp:
>>>
>>> <%@ page contentType="text/html; charset=UTF-8" %>
>>> <%@ taglib prefix="s" uri="/struts-tags" %>
>>> <!DOCTYPE html>
>>> <html>
>>> <head>
>>>       <title>File upload result</title>
>>> </head>
>>> <body>
>>> <h1>Hola Mundo desde la tierra...</h1>
>>> <form action="hello" method="post" enctype="multipart/form-data">
>>> <input type="text" name="name"/>
>>> <input type="text" name="lastname"/>
>>> <input type="text" name="gender"/>
>>> <input type="text" name="age"/>
>>>        <input type="file" name="*upload*"/>
>>>        <input type="submit" value="Subir" />
>>> </form>
>>> </body>
>>> </html>
>>>
>>> Expected Behavior:
>>>
>>> - When implementing UploadedFilesAware, the framework should:
>>> - Detect multipart requests
>>> - Process uploaded files through withUploadedFiles(List<UploadedFile>)
>>> - Make files available to the action
>>>
>>> Where my action looks like:
>>>
>>> import org.apache.logging.log4j.LogManager;
>>> import org.apache.logging.log4j.Logger;
>>> import org.apache.struts2.ActionSupport;
>>> import org.apache.struts2.action.UploadedFilesAware;
>>> import org.apache.struts2.dispatcher.multipart.UploadedFile;
>>> import org.apache.struts2.interceptor.parameter.StrutsParameter;
>>>
>>> public class HelloAction extends ActionSupport implements
>>> UploadedFilesAware {
>>>       private static final long serialVersionUID = 1L;
>>>       private Logger logger = LogManager.getLogger(HelloAction.class);
>>>
>>>       private UploadedFile upload;
>>>       private String uploadFileName;
>>>       private String uploadContentType;
>>>
>>>       @StrutsParameter(depth = 0)
>>>       public String name;
>>>
>>>       @StrutsParameter(depth = 0)
>>>       public String lastname;
>>>
>>>       @StrutsParameter(depth = 0)
>>>       public String gender;
>>>
>>>       @StrutsParameter(depth = 0)
>>>       public String age;
>>>
>>>       @Override
>>>       public String execute() {
>>>       logger.info("Executing execute method..." + this.uploadFileName);
>>>       return SUCCESS;
>>>       }
>>>       public UploadedFile getUpload() {
>>>           return upload;
>>>       }
>>>       public void setUpload(UploadedFile upload) {
>>>           this.upload = upload;
>>>       }
>>>       public String getUploadFileName() {
>>>           return uploadFileName;
>>>       }
>>>       public void setUploadFileName(String uploadFileName) {
>>>       this.uploadFileName = uploadFileName;
>>>       }
>>>       public String getUploadContentType() {
>>>           return uploadContentType;
>>>       }
>>>       public void setUploadContentType(String uploadContentType) {
>>>       this.uploadContentType = uploadContentType;
>>>       }
>>> public Logger getLogger() {
>>> return logger;
>>> }
>>> public void setLogger(Logger logger) {
>>> this.logger = logger;
>>> }
>>> public String getName() {
>>> return name;
>>> }
>>> public void setName(String name) {
>>> this.name = name;
>>> }
>>> public String getLastname() {
>>> return lastname;
>>> }
>>> public void setLastname(String lastname) {
>>> this.lastname = lastname;
>>> }
>>> public String getGender() {
>>> return gender;
>>> }
>>> public void setGender(String gender) {
>>> this.gender = gender;
>>> }
>>> public String getAge() {
>>> return age;
>>> }
>>> public void setAge(String age) {
>>> this.age = age;
>>> }
>>>
>>> @Override
>>>       public void withUploadedFiles(List<UploadedFile> uploadedFiles) {
>>>             if (uploadedFiles != null && !uploadedFiles.isEmpty()) {
>>>                UploadedFile firstFile = uploadedFiles.get(0); // Take the
>> file
>>>                this.upload = firstFile;
>>>                this.uploadFileName = firstFile.getName();     // String
>>>                this.uploadContentType = firstFile.getContentType(); //
>> String
>>>                logger.info("File name: " + uploadFileName);
>>>            }
>>>    }
>>>
>>> Actual Behavior:
>>> Despite proper multipart request detection:
>>>
>>> The interceptor finds the request wrapper:
>>>
>>> 2025-05-31 DEBUG ActionFileUploadInterceptor:200 - Found multipart
>> request:
>>> MultiPartRequestWrapper
>>>
>>> *Our custom DebugMultiPartRequest confirms file presence:*
>>>
>>> 2025-05-31 12:00:13 INFO  DebugMultiPartRequest:26 - Todos los parámetros
>>> del request:
>>> 2025-05-31 12:00:13 INFO  DebugMultiPartRequest:30 -  - nombre: Jesus
>>> 2025-05-31 12:00:13 INFO  DebugMultiPartRequest:30 -  - apellido: Moreno
>>> 2025-05-31 12:00:13 INFO  DebugMultiPartRequest:30 -  - sexo: M
>>> 2025-05-31 12:00:13 INFO  DebugMultiPartRequest:30 -  - edad: 50
>>>
>>>
>>>
>>> *2025-05-31 12:00:13 INFO  DebugMultiPartRequest:39 - Part 'upload'
>>> encontrada:2025-05-31 12:00:13 INFO  DebugMultiPartRequest:40 -  -
>> Nombre:
>>> Adaware.jpg2025-05-31 12:00:13 INFO  DebugMultiPartRequest:41 -  -
>> Tamaño:
>>> 25546*2025-05-31 12:00:13 DEBUG InstantiatingNullHandler:106 - Entering
>>> nullPropertyValue
>>> [target=[org.apache.struts2.text.DefaultTextProvider@2a580722],
>>> property=struts]
>>> 2025-05-31 12:00:13 DEBUG ConfigurationManager:180 - Checking
>>> ConfigurationProviders for reload.
>>> 2025-05-31 12:00:13 DEBUG InstantiatingNullHandler:106 - Entering
>>> nullPropertyValue
>>> [target=[org.apache.struts2.text.DefaultTextProvider@2a580722],
>>> property=struts]
>>> 2025-05-31 12:00:13 DEBUG DefaultActionProxy:88 - Creating an
>>> DefaultActionProxy for namespace [/] and action name [hello]
>>> 2025-05-31 12:00:14 DEBUG DefaultActionInvocation:310 - Executing
>>> conditional interceptor: ActionFileUploadInterceptor
>>> 2025-05-31 12:00:14 DEBUG ActionFileUploadInterceptor:200 - Found
>> multipart
>>> request: MultiPartRequestWrapper
>>>
>>> But the interceptor reports:
>>>
>>> *2025-05-31 12:00:14 DEBUG ActionFileUploadInterceptor:179 - No files
>> have
>>> been uploaded/accepted*
>>>
>>> Investigation Steps Taken:
>>>
>>> 1. Verified all prerequisites:
>>>      -  Form uses enctype="multipart/form-data"
>>>      -  Using DTD 6.0 as suggested
>>>      -  Regularly cleaning Tomcat's work directory
>>>      -  Confirmed Jakarta EE 9+ compatibility
>>>
>>> 2. Created extensive debug instrumentation:
>>>      -  Custom DebugMultiPartRequest shows files reach the server
>>>      -  Interceptor-level logging confirms the disconnect
>>>
>>> Technical Findings:
>>>
>>> 1. The MultiPartRequestWrapper appears to lose file references between:
>>>      -   Initial parsing (where files are detectable via raw Part API)
>>>      -   Interceptor processing phase
>>>
>>> 2. Key suspicious behavior:
>>>      -   getFileParameterNames() returns empty enumeration
>>>      -   Despite request.getPart("upload") working correctly
>>>
>>> Finally As you suggested, we've:
>>>
>>>       -  Consistently cleaned deployment directories
>>>       -  Verified DTD compatibility
>>>       -  Followed migration guides carefully
>>>       -  Yet the team remains persistent in investigating this apparent
>>> framework bug rather than working around it.
>>>
>>> # Summary
>>> Files are received by the server (confirmed via custom
>>> DebugMultiPartRequest) but ActionFileUploadInterceptor fails to process
>>> them via UploadedFilesAware interface in Struts 7.0.3 (Jakarta EE
>> 9/Tomcat
>>> 10 environment).
>>>
>>> This is my custom DebugMultiPartRequest:
>>>
>>> public class DebugMultiPartRequest extends JakartaMultiPartRequest {
>>> private static final Logger logger =
>>> LogManager.getLogger(DebugMultiPartRequest.class);
>>>    @Override
>>>      public void parse(HttpServletRequest request, String saveDir) throws
>>> IOException {
>>>          super.parse(request, saveDir); // Procesa el request normalmente
>>>          logger.info("=== DebugMultiPartRequest (Struts 7) ===");
>>>          // 1. Listar TODOS los parámetros del request (no solo archivos)
>>>          logger.info("Todos los parámetros del request:");
>>>          Enumeration<String> paramNames = request.getParameterNames();
>>>          while (paramNames.hasMoreElements()) {
>>>              String name = paramNames.nextElement();
>>>              logger.info(" - " + name + ": " +
>> request.getParameter(name));
>>>          }
>>>         // 2. Listar partes multipart (alternativa para Jakarta EE 9+)
>>>          if (request instanceof jakarta.servlet.http.HttpServletRequest
>>> jakartaRequest) {
>>>              jakarta.servlet.http.Part part;
>>> try {
>>> part = jakartaRequest.getPart("upload");
>>> if (part != null) {
>>>
>>>
>>>
>>> * logger.info<http://logger.info>("Part 'upload' encontrada:");
>>> logger.info<http://logger.info>(" - Nombre: " +
>>> part.getSubmittedFileName()); logger.info<http://logger.info>(" -
>> Tamaño:
>>> " + part.getSize());*            } else {
>>>               logger.info("❌ Parte 'upload' NO encontrada en el
>> request.");
>>>              }
>>> } catch (IOException e) {
>>> // TODO Auto-generated catch block
>>> e.printStackTrace();
>>> } catch (ServletException e) {
>>> // TODO Auto-generated catch block
>>> e.printStackTrace();
>>> } // Nombre de tu campo
>>>
>>>          }
>>>         }
>>> }
>>>
>>> After this investigation, we appreciated your feedback if there's any
>>> version where this issue we've identified has been resolved, or how we
>> can
>>> make file uploads work properly.
>>>
>>> Regards
>>> JMC
>>>
>>>
>>> El mié, 14 may 2025 a las 0:09, Lukasz Lenart (<[email protected]
>>> )
>>> escribió:
>>>
>>>> sob., 10 maj 2025 o 07:09 Jesus Moreno<[email protected]> napisał(a):
>>>>> 2025-05-09 01:00:25 WARNFile:79 - Struts has detected a file upload UI
>>>> tag
>>>>> (s:file) being used without a form set to method 'POST'
>>>>> (Despite <s:form method="POST" enctype="multipart/form-data"> being
>>>>> correctly declared)
>>>> This can be related to cached JSP files, please remove them from the
>>>> container "temp" folder or "work" folder.
>>>>
>>>>
>> https://cwiki.apache.org/confluence/display/WW/Struts+6.x.x+to+7.x.x+migration#Struts6.x.xto7.x.xmigration-Temp/WorkdirectoryofApplicationServer/ServletContainer
>>>>> struts.xml:
>>>>> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts
>>>>> Configuration 6.5//EN"
>>>>>       "https://struts.apache.org/dtds/struts-6.5.dtd">
>>>> There is no such version as 6.5, use 6.0 instead
>>>> https://struts.apache.org/dtds/
>>>>
>>>>
>>>> Cheers
>>>> Łukasz
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe,e-mail:[email protected]
>>>> For additional commands,e-mail:[email protected]
>>>>
>>>>
>
>