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]
>>
>>