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

Zoran Avtarovski <[email protected]> Tue, 3 Jun 2025 15:43:19 +1000
Newsgroups gmane.comp.jakarta.struts.user
Message-ID <[email protected]>
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]
>>
>>