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 (<zo...@sparecreative.com>)
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 (<lukaszlen...@apache.org
)
escribió:

sob., 10 maj 2025 o 07:09 Jesus Moreno<jesus...@gmail.com> 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:user-unsubscr...@struts.apache.org
For additional commands,e-mail:user-h...@struts.apache.org



Reply via email to