Top 60 Struts Interview Questions (2026)

The 60 Apache Struts questions interviewers actually ask, with direct answers, runnable config and code, and what the interviewer is listening for. Grouped for freshers, intermediate, and experienced rounds.

60 questions with answers

What Is Struts?

Key Takeaways

  • Apache Struts is a Java web framework that puts the Model-View-Controller pattern behind servlets and JSP so request handling stays organized.
  • Struts 2 is the current line and a rewrite of Struts 1: POJO actions, interceptors, OGNL, and the value stack replace the old ActionForm and Action base classes.
  • Interviews test whether you understand the request lifecycle (FilterDispatcher to interceptors to action to result), not just XML syntax you can look up.
  • This page is a question bank: work your tier first, read one tier up, and say answers out loud because delivery is evaluated too.

Apache Struts is an open-source Java framework for building web applications on the Model-View-Controller pattern, maintained by the Apache Software Foundation. It sits on top of the servlet and JSP layer and gives request handling a clear structure: a front controller receives the request, routes it to an action, and hands the result to a view. There are two lines. Struts 1, released in 2000, used an ActionServlet, ActionForm beans, and Action classes wired through struts-config.xml. Struts 2, released in 2007, is a ground-up rewrite based on the older WebWork project; it uses plain POJO actions, an interceptor stack for cross-cutting work, OGNL for data access, and the value stack for passing data to views. Most interviews mean Struts 2 when they say Struts. According to the official Apache Struts documentation, the framework's job is to keep the controller, model, and view concerns separate so applications stay maintainable as they grow. In interviews, questions probe the request lifecycle, interceptors, OGNL and the value stack, validation, and the Struts 1 to Struts 2 migration, plus the security history that makes version awareness matter. This page collects the 60 questions that come up most, each with a direct answer and runnable config or code. Increasingly the first backend round is a live AI coding interview, so pair this bank with our AI interview preparation guides for the format side.

60Questions with answers on this page
3Difficulty tiers: freshers, intermediate, experienced
22Runnable code and config snippets you can practice from
MVCStruts is a Java MVC web framework built on servlets and JSP

Watch: Struts 2 Tutorial 01 - Introduction To MVC

Video: Struts 2 Tutorial 01 - Introduction To MVC (Java Brains, YouTube)

Test yourself and earn a certificate

10 quick questions. Score 70%+ to download your Struts certificate.

Jump to quiz

All Questions on This Page

60 questions
Struts Interview Questions for Freshers
  1. 1. What is Apache Struts and what problem does it solve?
  2. 2. What is the MVC pattern and how does Struts map to it?
  3. 3. What is the difference between Struts 1 and Struts 2?
  4. 4. What is the front controller in Struts 2 and how is it configured?
  5. 5. What is an action class in Struts 2?
  6. 6. What is struts.xml and what goes in it?
  7. 7. Walk through the Struts 2 request lifecycle.
  8. 8. What are interceptors in Struts 2?
  9. 9. What is the value stack in Struts 2?
  10. 10. What is OGNL and where is it used in Struts 2?
  11. 11. What is a result and what result types does Struts 2 offer?
  12. 12. What is ActionSupport and why extend it?
  13. 13. How does form data get onto an action in Struts 2?
  14. 14. What are Struts tags and why use them over plain HTML?
  15. 15. How do you validate input in Struts 2?
  16. 16. What is the "input" result and when is it used?
  17. 17. What is ActionContext in Struts 2?
  18. 18. How do you access the session in a Struts 2 action?
  19. 19. Why is Struts version awareness a security topic?
  20. 20. What is the role of web.xml in a Struts 2 application?
Struts Intermediate Interview Questions
  1. 21. How does the interceptor stack work, and what order do interceptors run in?
  2. 22. How do you write a custom interceptor?
  3. 23. How does OGNL interact with the value stack in detail?
  4. 24. How does XML/declarative validation work in Struts 2?
  5. 25. When do you choose programmatic validate() over declarative validation?
  6. 26. What are namespaces in Struts 2 configuration?
  7. 27. What is action chaining and when is it a bad idea?
  8. 28. How do wildcard action mappings work?
  9. 29. What is Dynamic Method Invocation and why is it off by default?
  10. 30. What does the Preparable interface do?
  11. 31. What is the ModelDriven interface?
  12. 32. How does internationalization work in Struts 2?
  13. 33. How does file upload work in Struts 2?
  14. 34. How do you handle exceptions declaratively in Struts 2?
  15. 35. How does annotation-based configuration and the convention plugin work?
  16. 36. What does Struts give you over writing plain servlets and JSP?
  17. 37. How does Struts 2 compare to Spring MVC?
  18. 38. How do you integrate Struts 2 with Spring?
  19. 39. Are Struts 2 actions thread-safe, and why?
  20. 40. How do you build a JSON API endpoint in Struts 2?
  21. 41. What is struts.devMode and what does it change?
  22. 42. How does package inheritance work in struts.xml, and why does it matter?
Struts Interview Questions for Experienced Developers
  1. 43. Explain the OGNL injection class of Struts vulnerabilities and how to defend against them.
  2. 44. How would you migrate a Struts 1 application to Struts 2?
  3. 45. How does ActionInvocation drive the interceptor chain internally?
  4. 46. How do you write a custom result type, and when is it worth it?
  5. 47. How does the value stack resolve properties, and what are the performance implications?
  6. 48. How do you unit test Struts 2 actions?
  7. 49. How do you approach performance tuning in a Struts 2 application?
  8. 50. How do you organize configuration across a large Struts 2 codebase?
  9. 51. How does type conversion work in Struts 2, and how do you customize it?
  10. 52. What is the difference between global and local results, and when do you use each?
  11. 53. How do you handle type conversion and validation errors together cleanly?
  12. 54. How do Struts 2 apps fit modern deployment, containers, and async work?
  13. 55. What is XWork and how does it relate to Struts 2?
  14. 56. How do Struts UI tag themes work, and how would you customize them?
  15. 57. How do ActionContext, ServletActionContext, and the value stack relate?
  16. 58. When would you recommend against using Struts for a new project?
  17. 59. How does Struts 2 decide configuration when XML, annotations, and defaults all apply?
  18. 60. How do you carry state across requests in a multi-step Struts 2 wizard?

Struts Interview Questions for Freshers

Freshers20 questions

The fundamentals every entry-level round checks. If any answer here surprises you, that's your study list.

Q1. What is Apache Struts and what problem does it solve?

Struts is an open-source Java framework for building web applications on the Model-View-Controller pattern, maintained by the Apache Software Foundation. It sits on top of servlets and JSP and gives request handling a clear structure.

The problem it solves is the tangle you get when business logic, HTML, and request routing all live in the same JSP or servlet. Struts pushes routing into a front controller, logic into action classes, and presentation into views, so a growing app stays maintainable.

Key point: A one-line definition plus the problem it solves (separation of concerns in Java web apps) beats a memorized feature list. Interviewers open with this to hear how you frame an answer.

Watch a deeper explanation

Video: java struts tutorial|Java Framework|Struts2.X Part - 1 by Naveen (Durga Software Solutions, YouTube)

Q2. What is the MVC pattern and how does Struts map to it?

MVC splits an app into three parts: the Model holds data and business logic, the View renders output, and the Controller handles input and coordinates the other two. The point is that each part changes independently.

In Struts 2 the controller is the front-controller filter plus the interceptor stack, the model is your action's data and the services it calls, and the view is a JSP or other result type. The action itself sits between them: it takes populated data, runs logic, and returns a result name.

MVC roleStruts 2 pieceJob
ControllerFront-controller filter + interceptorsReceive the request, route it, run cross-cutting work
ModelAction data + service/DAO layerHold state and business logic
ViewJSP / FreeMarker / result typeRender the response

Key point: the question needs you to place the action correctly. Saying the action is 'the controller' is a common slip; it's better described as the request handler that sits between the controller layer and the model.

Q3. What is the difference between Struts 1 and Struts 2?

Struts 2 isn't an upgrade of Struts 1; it's a rewrite based on the WebWork project that kept the Struts name. Struts 1 used an ActionServlet, ActionForm beans, and Action classes you had to extend. Struts 2 uses a filter front controller, POJO actions with no required base class, interceptors, and OGNL.

Practically: Struts 1 shared one Action instance across requests (forcing stateless code), while Struts 2 creates a new action per request. Struts 1 kept form data in a separate ActionForm; Struts 2 puts properties on the action itself.

Key point: Naming three concrete differences (instance-per-request, POJO actions, interceptors) is the bar. Vague 'Struts 2 is better' answers get a follow-up.

Q4. What is the front controller in Struts 2 and how is it configured?

The front controller is a servlet filter that receives every request, decides which action handles it, runs the interceptor stack, invokes the action, and renders the result. In current Struts 2 it's StrutsPrepareAndExecuteFilter; older versions used FilterDispatcher.

You register it in web.xml (or via the Servlet container's programmatic config) so it maps to the URL pattern your app uses, usually /*.

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

Key point: Knowing it's a filter in Struts 2 (not the ActionServlet of Struts 1) is the distinction the key signal is.

Watch a deeper explanation

Video: Struts 2 Tutorial 03 - Setting Up (Java Brains, YouTube)

Q5. What is an action class in Struts 2?

An action is a plain Java object that handles a request. It holds the request data as properties (with getters and setters) and exposes a method, usually execute(), that runs your logic and returns a result name like "success".

It doesn't have to extend anything, though most extend ActionSupport for validation, i18n, and the result-name constants. Because Struts 2 creates a new action per request, you can safely store request state in instance fields.

java
public class HelloAction extends ActionSupport {
    private String name;

    public String execute() {
        return SUCCESS;   // maps to a result in struts.xml
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

Q6. What is struts.xml and what goes in it?

struts.xml is the main configuration file for a Struts 2 app. It defines packages, action mappings (which URL maps to which action class and method), results (what to render for each result name), and interceptor stacks.

It usually lives on the classpath at src/main/resources. Annotations and the convention plugin can replace much of it, but the XML is what most interview examples use.

xml
<struts>
  <package name="default" extends="struts-default">
    <action name="hello" class="com.example.HelloAction">
      <result name="success">/hello.jsp</result>
      <result name="input">/form.jsp</result>
    </action>
  </package>
</struts>

Key point: The extends="struts-default" detail matters: it pulls in the default interceptor stack. Leaving it out is a classic 'nothing works' bug.

Q7. Walk through the Struts 2 request lifecycle.

A request hits the front-controller filter, which consults the configuration to find the matching action mapping. It creates a new action instance, then runs the interceptor stack in order: interceptors handle parameter population, validation, file upload, and more before the action executes.

The action's method runs and returns a result name. Struts maps that name to a result (often a JSP), renders it, and the interceptors run again on the way back out. The value stack carries data throughout so the view can read it via OGNL.

Struts 2 request lifecycle

1Filter receives request
front controller matches the URL to an action mapping
2Interceptor stack runs
params, validation, file upload, and other cross-cutting work
3Action executes
logic runs, returns a result name like success or input
4Result renders
result name maps to a JSP or other result, value stack feeds the view

Interceptors run on the way in and again on the way out, wrapping the action like layers of an onion.

Q8. What are interceptors in Struts 2?

Interceptors are components that run before and after an action to handle cross-cutting concerns: populating request parameters onto the action, running validation, handling file uploads, managing the conversation scope, exception handling, and more. They're configured in a stack that defines execution order.

This is the piece that replaces the hardcoded controller plumbing of Struts 1. Because they're pluggable, you add or remove behavior by editing the stack rather than the action code.

Key point: Naming two or three real interceptors (params, validation, fileUpload) shows you've seen a stack, not just read the word 'interceptor'.

Watch a deeper explanation

Video: Struts 2 Tutorial 16 - Introducing Interceptors (Java Brains, YouTube)

Q9. What is the value stack in Struts 2?

The value stack is a stack of objects Struts keeps for each request, with the current action usually on top. Views and configuration read and write data on it through OGNL, so a JSP tag like <s:property value="name"/> reaches into the action's name property without you wiring it up.

It's part of the ActionContext, the thread-local bag that holds everything about the current request. The stack is why you rarely touch the raw HttpServletRequest in Struts 2.

Q10. What is OGNL and where is it used in Struts 2?

OGNL, Object-Graph Navigation Language, is the expression language Struts 2 uses to read and write properties on the value stack. When a JSP tag says value="user.email", OGNL walks from the top of the stack to the user object's email property.

It runs form binding, tag output, and dynamic configuration. Because OGNL can call methods and reach into object graphs, careless exposure of user-controlled OGNL is also the root of several Struts security holes, which is why version patching matters.

jsp
<%-- reads name off the value stack (the action) --%>
<s:property value="name"/>

<%-- navigates an object graph --%>
<s:property value="user.address.city"/>

Q11. What is a result and what result types does Struts 2 offer?

A result is what Struts renders after an action returns a result name. The mapping from name to result lives in configuration. The default result type is dispatcher, which forwards to a JSP, but there are many others.

Common types: dispatcher (forward to JSP), redirect (browser redirect to a URL), redirectAction (redirect to another action), stream (send bytes, for downloads), json (with the JSON plugin), and freemarker.

Result typeWhat it doesTypical use
dispatcherForwards to a JSP (default)Render a normal page
redirectSends an HTTP redirect to a URLPost-redirect-get, external links
redirectActionRedirects to another actionChaining flows after a form submit
streamWrites raw bytes to the responseFile downloads
jsonSerializes the action to JSONAJAX endpoints (JSON plugin)

Q12. What is ActionSupport and why extend it?

ActionSupport is a convenience base class that implements several useful interfaces at once: Action (with the SUCCESS, INPUT, ERROR, LOGIN, NONE result constants), Validateable and ValidationAware (for the validate hook and field error collection), and TextProvider and LocaleProvider (for internationalization and message lookup).

You extend it so you get validate(), addFieldError(), getText() for i18n, and the result constants for free. You're never required to; a POJO with an execute() method works, but you'd reimplement what ActionSupport gives you.

Q13. How does form data get onto an action in Struts 2?

The params interceptor (part of the default stack) reads request parameters and sets matching properties on the action via their setters, using OGNL. A form field named email calls setEmail on the action. Nested names like user.email walk into an object.

So there's no separate ActionForm like in Struts 1: the action itself holds the form data. You just add the field, the getter, and the setter.

java
// <input name="user.email"> populates this automatically
public class SignupAction extends ActionSupport {
    private User user = new User();
    public User getUser() { return user; }
    public void setUser(User user) { this.user = user; }
}

Q14. What are Struts tags and why use them over plain HTML?

Struts ships a JSP tag library (the s: prefix) for forms, control flow, and output: <s:form>, <s:textfield>, <s:property>, <s:iterator>, <s:if>. The tags read and write the value stack through OGNL, so they bind to action properties without manual wiring.

They also handle theming, field error display, and internationalization. Plain HTML works, but you'd lose automatic value binding and the built-in error markup.

jsp
<s:form action="signup">
  <s:textfield name="user.email" label="Email"/>
  <s:password name="user.password" label="Password"/>
  <s:submit value="Sign up"/>
</s:form>

Q15. How do you validate input in Struts 2?

Two main ways. Programmatic: override validate() in an action that extends ActionSupport and call addFieldError for each problem; if any errors exist, Struts routes to the input result instead of running the action. Declarative: an XML validation file or annotations describe rules and the validation interceptor applies them.

Both rely on the validation and workflow interceptors in the default stack, and both send failures back to the input result so the user sees their form again with messages.

java
public void validate() {
    if (name == null || name.trim().isEmpty()) {
        addFieldError("name", "Name is required");
    }
    if (age < 18) {
        addFieldError("age", "Must be 18 or older");
    }
}

Key point: Mentioning that validation failures need an <result name="input"> mapping to actually show up is the detail that trips people in practice.

Q16. What is the "input" result and when is it used?

The input result is where the workflow interceptor sends the request when validation fails. Instead of running the action, Struts renders whatever you mapped to the name "input", normally the form page, so the user can fix their input.

If you validate but forget to map an input result, Struts throws an error because it has nowhere to route the failure. That's a frequent beginner bug.

Q17. What is ActionContext in Struts 2?

ActionContext is a thread-local container holding everything about the current request: the value stack, request and session parameters, the locale, and the application context. Because it's thread-local, your action reads context without being handed the raw servlet objects.

You reach it with ActionContext.getContext(). It's how Struts keeps actions decoupled from the servlet API while still giving access to session and request data when you need it.

Q18. How do you access the session in a Struts 2 action?

The clean way is to implement SessionAware, which asks Struts to inject a Map view of the session via setSession before the action runs. That keeps the action testable and free of a direct servlet dependency, because you can pass a plain map in a unit test instead of mocking the container.

You can also pull it from ActionContext.getContext().getSession(). Reaching for the raw HttpServletRequest via ServletRequestAware works too but couples the action to the servlet API, which interviewers note as the less clean option.

java
public class CartAction extends ActionSupport implements SessionAware {
    private Map<String, Object> session;
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }
    public String execute() {
        session.put("lastVisit", System.currentTimeMillis());
        return SUCCESS;
    }
}

Q19. Why is Struts version awareness a security topic?

Struts 2 had several high-severity remote-code-execution vulnerabilities over the years, many tied to OGNL expressions being evaluated on user-controlled input. Unpatched Struts apps have caused large real-world breaches, so which version you run is a security decision, not just a compatibility one, and interviewers ask about it deliberately.

The interview point is practical: run a maintained, patched version, watch Apache security bulletins, and don't expose user input to OGNL evaluation. Showing you know Struts needs active patching, not set-and-forget, indicates production maturity.

Key point: You don't need CVE numbers. Knowing the class of problem (OGNL injection) and the fix (stay patched) is what this screens for.

Q20. What is the role of web.xml in a Struts 2 application?

web.xml is the servlet container's deployment descriptor, and in a Struts 2 app its main job is registering the front-controller filter and mapping it to a URL pattern (usually /*). That single filter registration is what routes every request into Struts.

It can also hold container-level config like listeners (for Spring), welcome files, and error pages. Most of the app's routing lives in struts.xml instead, so web.xml stays small: it hands requests to the filter and gets out of the way.

Key point: The distinction the key signal is is web.xml (container config, registers the filter) versus struts.xml (action routing). Mixing up which file does what is a common slip.

Back to question list

Struts Intermediate Interview Questions

Intermediate22 questions

For candidates with working experience: interceptor mechanics, OGNL depth, validation, and the configuration judgment that separates users from understanders.

Q21. How does the interceptor stack work, and what order do interceptors run in?

Interceptors are chained like layers of an onion. Each interceptor gets the ActionInvocation, does its before-work, calls invocation.invoke() to pass control inward, then does its after-work when control returns. So the order in is the reverse of the order out.

The stack is defined in configuration, and the order matters: params must run before validation, and validation before the action. The struts-default stack orders the common interceptors correctly, which is why most packages extend it.

xml
<interceptor-stack name="myStack">
  <interceptor-ref name="exception"/>
  <interceptor-ref name="params"/>
  <interceptor-ref name="validation"/>
  <interceptor-ref name="workflow"/>
</interceptor-stack>

Key point: The onion model plus invoke() is the answer. If you can explain that before-code runs top-down and after-code runs bottom-up, you understand the mechanism.

Watch a deeper explanation

Video: Struts 2 Tutorial 18 - Anatomy of an Interceptor (Java Brains, YouTube)

Q22. How do you write a custom interceptor?

Implement the Interceptor interface (or extend AbstractInterceptor to skip the lifecycle methods) and put your logic in intercept(ActionInvocation). Do your before-work, call invocation.invoke() to continue the chain, then do after-work with the returned result.

Register it in struts.xml and add it to a stack. Common uses: audit logging, custom auth checks, request timing. If you skip invoke() and return a result name instead, you short-circuit the chain, which is how a login interceptor blocks unauthenticated requests.

java
public class AuthInterceptor extends AbstractInterceptor {
    public String intercept(ActionInvocation inv) throws Exception {
        Map<String, Object> session = inv.getInvocationContext().getSession();
        if (session.get("user") == null) {
            return Action.LOGIN;   // short-circuit: skip the action
        }
        return inv.invoke();       // continue the chain
    }
}

Key point: The short-circuit trick (return a result instead of calling invoke) is the follow-up. It's how auth and rate-limiting interceptors work.

Q23. How does OGNL interact with the value stack in detail?

OGNL expressions are evaluated against the value stack's top object first, then down the stack, so an unqualified name like email resolves against the action if the action has it. The stack is the root object, so top-level names search each stacked object in order.

The # prefix reaches named context objects instead of the stack: #session, #request, #parameters, and #attr. So value="name" reads the action's name, while value="#session.user" reaches the session map.

jsp
<%-- from the value stack (action property) --%>
<s:property value="orderTotal"/>

<%-- from named context objects with # --%>
<s:property value="#session.username"/>
<s:property value="#parameters.page"/>

Q24. How does XML/declarative validation work in Struts 2?

You put a validation file named ActionClass-validation.xml next to the action. It declares field validators (required, stringlength, email, int range, regex) with messages. The validation interceptor reads it and applies the rules before the action runs.

It keeps rules out of Java and lets you reuse validators. Failures collect as field errors and route to the input result, same as programmatic validate().

xml
<validators>
  <field name="email">
    <field-validator type="requiredstring">
      <message>Email is required</message>
    </field-validator>
    <field-validator type="email">
      <message>Enter a valid email</message>
    </field-validator>
  </field>
</validators>

Q25. When do you choose programmatic validate() over declarative validation?

Declarative XML validation fits standard, per-field rules: required, length, format, range. It's reusable, readable, and keeps the action clean, so reach for it first for ordinary form checks where the rule depends on one field and nothing else in the request.

Programmatic validate() fits cross-field and conditional logic: password matches confirmation, end date after start date, a rule that only applies when another field is set. Those are awkward in XML, so put them in Java.

ConcernDeclarative XMLProgrammatic validate()
Single-field rulesBest fitOverkill
Cross-field logicAwkwardBest fit
Reuse across actionsEasyManual
ReadabilityRules in one fileLogic near the action

Key point: The production-ready answer is 'both': declarative for the routine fields, validate() for the conditional and cross-field checks. Picking one dogmatically is the weaker response.

Q26. What are namespaces in Struts 2 configuration?

A namespace maps a package of actions to a URL prefix, so /admin/deleteUser and /user/deleteUser can coexist as different actions. You set namespace on the package element; the default namespace is empty (root).

Namespaces organize large apps and are also a natural boundary for applying different interceptor stacks, for example an auth interceptor on the whole /admin namespace.

xml
<package name="admin" namespace="/admin" extends="struts-default">
  <action name="dashboard" class="com.example.admin.DashboardAction">
    <result>/admin/dashboard.jsp</result>
  </action>
</package>

Q27. What is action chaining and when is it a bad idea?

Action chaining uses the chain result type to forward from one action to another within the same request, copying properties from the first action onto the second via the chaining interceptor. It looks convenient for reusing an action's work.

It's usually discouraged: the copied state is implicit and fragile, it breaks the browser's URL/refresh model, and it couples actions tightly. Prefer redirectAction (a clean redirect) or extracting shared logic into a service both actions call.

Key point: Interviewers often ask this to see if you know the anti-pattern. Recommending a shared service or redirectAction over chaining is the answer they want.

Q28. How do wildcard action mappings work?

You can use * in an action name to match a pattern and reuse the captured part with {1}, {2} in the class or method. So one mapping can route userAdd, userEdit, userDelete to methods on a single action.

It cuts repetitive config, but overusing it hides which URLs exist. A little wildcarding for CRUD variants is fine; wildcarding everything makes the config hard to read.

xml
<action name="user_*" class="com.example.UserAction" method="{1}">
  <result name="success">/user/{1}.jsp</result>
</action>
<!-- user_add calls add(), renders /user/add.jsp -->

Q29. What is Dynamic Method Invocation and why is it off by default?

Dynamic Method Invocation (DMI) lets the incoming URL pick which action method runs using the action!method syntax, like user!delete calling the delete method. It saves writing a separate mapping for each method, which looks convenient for a CRUD action with several entry points.

It's disabled by default because it widens the attack surface: letting the URL name arbitrary methods has been part of Struts exploits. If you enable it, restrict it and prefer explicit method attributes or wildcard mappings instead.

Q30. What does the Preparable interface do?

Preparable adds a prepare() method that the prepare interceptor calls before parameters are set on the action. You use it to load objects the request will populate, for example fetching the existing entity by id so form fields update it rather than creating a blank one.

It's the hook for the load-then-populate pattern in edit flows, and it runs early enough that the params interceptor can bind form values onto the loaded object.

java
public class EditUserAction extends ActionSupport implements Preparable {
    private Long id;
    private User user;
    public void prepare() {
        user = (id != null) ? userService.find(id) : new User();
    }
    // params interceptor then sets user.* fields on the loaded object
}

Q31. What is the ModelDriven interface?

ModelDriven lets you push a model object to the top of the value stack so form fields bind directly to model.field instead of action.model.field. You implement getModel() to return the object, and the modelDriven interceptor stacks it.

It cleans up form binding when an action wraps a single domain object. The trade-off: the model sits above the action on the stack, which can surprise people debugging OGNL resolution, so use it deliberately.

java
public class SaveUserAction extends ActionSupport
        implements ModelDriven<User> {
    private User user = new User();
    public User getModel() { return user; }
    // form field name="email" now binds to user.email
}

Q32. How does internationalization work in Struts 2?

You put message keys in resource bundle properties files (package.properties, package_fr.properties) and read them with getText("key") in actions or <s:text name="key"/> in JSPs. ActionSupport provides getText via TextProvider, and Struts picks the bundle by locale.

The i18n interceptor tracks the user's locale (from a request parameter or session), so switching language is a matter of changing that locale, not the code.

Q33. How does file upload work in Struts 2?

The fileUpload interceptor (in the default stack) parses multipart requests and hands your action three properties per file field: the File itself (name matching the field), plus [field]FileName and [field]ContentType. You add matching getters and setters.

You control limits with struts.multipart.maxSize and the interceptor's allowed types and extensions. The uploaded file is a temp file, so you copy it somewhere permanent in the action.

java
public class UploadAction extends ActionSupport {
    private File upload;
    private String uploadFileName;
    private String uploadContentType;
    // getters/setters omitted
    public String execute() throws Exception {
        FileUtils.copyFile(upload, new File("/data/" + uploadFileName));
        return SUCCESS;
    }
}

Q34. How do you handle exceptions declaratively in Struts 2?

The exception interceptor (first in the default stack) catches exceptions the action throws and maps them to results. You declare exception-mapping entries, globally or per action, that an exception type maps to a result name like "error".

This keeps try/catch out of actions for expected failure paths and gives a consistent error page. The caught exception lands on the value stack as exception and exceptionStack so the error JSP can display details.

xml
<global-exception-mappings>
  <exception-mapping exception="java.lang.Exception"
                     result="error"/>
</global-exception-mappings>
<global-results>
  <result name="error">/error.jsp</result>
</global-results>

Q35. How does annotation-based configuration and the convention plugin work?

The convention plugin infers configuration from class names and package locations, so an action class named HelloAction in a conventional package maps to /hello with a matching JSP, no struts.xml entry needed. Annotations like @Action, @Result, and @Namespace override the conventions where you need explicit control.

It cuts XML sharply for teams that like convention over configuration. The trade-off is that the routing is implicit, so newcomers have to learn the conventions to find where a URL goes.

Q36. What does Struts give you over writing plain servlets and JSP?

Plain servlets force you to parse parameters, manage dispatch, and handle validation and errors by hand in every servlet. Struts factors all of that into the framework: automatic parameter binding, a declarative action-to-result mapping, an interceptor stack for cross-cutting work, and a tag library that binds views to data.

The cost is a framework to learn and configuration to maintain. For a two-page app that's overhead; for a form-heavy business app it removes a lot of repetitive plumbing.

ConcernPlain servlets + JSPStruts 2
Parameter bindingManual request.getParameterAutomatic via params interceptor
Request routingweb.xml + hand-written dispatchDeclarative action mappings
Cross-cutting logicRepeated in each servletInterceptor stack
ValidationHand-writtenDeclarative or validate()
View data bindingScriptlets / EL by handStruts tags + OGNL

Q37. How does Struts 2 compare to Spring MVC?

Both are MVC web frameworks with a front controller and annotated or configured handlers. Spring MVC integrates natively with the wider Spring ecosystem (dependency injection, data, security, Boot) and is the common default for new Java web work today. Struts 2 is a capable MVC framework but mostly lives in existing apps now.

The honest interview answer: for greenfield work most teams reach for Spring MVC or Spring Boot; Struts skills are valuable for maintaining and migrating the large base of existing Struts applications. Saying that indicates current rather than defensive.

Key point: Interviewers testing seniority want to hear you place Struts accurately, a maintenance and migration skill, rather than oversell it against Spring.

Q38. How do you integrate Struts 2 with Spring?

The struts2-spring-plugin lets Spring manage your action instances and inject dependencies (services, DAOs) into them. You register the Spring ContextLoaderListener, add the plugin, and set the ObjectFactory to Spring so Struts asks Spring to create actions.

After that, actions become Spring beans: you autowire a service into an action instead of newing it up, which makes actions testable and keeps wiring in one place.

xml
<!-- web.xml -->
<listener>
  <listener-class>
    org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>
<!-- with struts2-spring-plugin on the classpath, actions are Spring-managed -->

Q39. Are Struts 2 actions thread-safe, and why?

Yes, by default, because Struts 2 creates a new action instance for every request. Two concurrent requests get two separate objects, so instance fields holding request data don't collide. This is a direct improvement over Struts 1, which shared one Action instance and forced stateless code.

The caveat: shared dependencies you inject (a service, a cache, a static field) are still shared across requests, so those must be thread-safe themselves. The per-request instance protects request state, not everything the action touches.

Key point: The contrast with Struts 1's single shared Action instance is the point of the question. Note the injected-dependency caveat and you've given the full answer.

Q40. How do you build a JSON API endpoint in Struts 2?

Add the struts2-json-plugin, extend the json-default package, and use the json result type. The plugin serializes the action's properties (or a named root object) to JSON, so your action just sets fields and returns success.

You control which fields serialize with includeProperties or excludeProperties parameters on the result. It's how Struts apps expose AJAX endpoints without hand-writing serialization.

xml
<package name="api" extends="json-default">
  <action name="user" class="com.example.UserApiAction">
    <result type="json">
      <param name="root">user</param>
    </result>
  </action>
</package>

Q41. What is struts.devMode and what does it change?

Setting struts.devMode to true turns on development conveniences: configuration reloads without a container restart, more detailed error pages, and OGNL and localization warnings surfaced instead of swallowed. It speeds up the edit-refresh loop when you're wiring actions and results and something isn't binding.

It's strictly for development. In production it hurts performance and leaks internal detail in errors, so you turn it off. Interviewers sometimes ask this to check you know it's a dev-only switch.

Q42. How does package inheritance work in struts.xml, and why does it matter?

A package can extend another with the extends attribute, inheriting its interceptor stacks, result types, and global results. Almost every package extends struts-default (from struts-default.xml), which is where the default interceptor stack and standard result types come from. Miss that extends and your actions get no parameter binding or validation.

You use inheritance to define a base package once (a shared auth stack, common global results, a custom result type) and have feature packages extend it. That keeps configuration DRY across modules and makes a cross-cutting change one edit instead of many.

xml
<package name="base" extends="struts-default" abstract="true">
  <interceptor-stack name="secured">
    <interceptor-ref name="auth"/>
    <interceptor-ref name="defaultStack"/>
  </interceptor-stack>
  <global-results><result name="login">/login.jsp</result></global-results>
</package>

<package name="admin" namespace="/admin" extends="base">
  <!-- inherits the secured stack and login result -->
</package>

Key point: The 'forgot extends=struts-default so nothing binds' bug is a favorite follow-up. Naming it shows you've debugged real config, not just read the docs.

Back to question list

Struts Interview Questions for Experienced Developers

Experienced18 questions

advanced rounds probe internals, security history, migration judgment, and production scars. Expect every answer here to draw a follow-up.

Q43. Explain the OGNL injection class of Struts vulnerabilities and how to defend against them.

Several severe Struts 2 remote-code-execution flaws came from user-controlled input being evaluated as OGNL. Because OGNL can call methods and reach the runtime, an attacker who gets an OGNL expression evaluated can run arbitrary code on the server. Some flaws were in how the framework itself parsed certain inputs (error messages, Content-Type headers, tag attributes).

Defenses: stay on a patched Struts version and watch Apache security bulletins, never pass user input into OGNL evaluation or dynamic tag attributes, avoid features like Dynamic Method Invocation unless restricted, and keep the OGNL and framework config locked down. This is the security topic senior interviews expect you to speak to concretely.

Key point: You don't need CVE numbers, but naming the pattern (untrusted input reaching OGNL) and the layered defenses (patch, don't evaluate user input, restrict DMI) is what separates The production-ready answer here.

Watch a deeper explanation

Video: Simple Apache Struts 2.5 Example (Cameron McKenzie, YouTube)

Q44. How would you migrate a Struts 1 application to Struts 2?

It's a rewrite of the web tier, not a config swap, because the models differ. Plan it incrementally: run both frameworks side by side (Struts 1 and Struts 2 can coexist in one web app with different URL mappings) and migrate feature by feature rather than big-bang.

Per feature: convert Action classes to POJO actions, fold ActionForm data into action properties, replace struts-config.xml mappings with struts.xml or annotations, swap the Struts 1 tags for Struts 2 tags with OGNL, and move validation to validate() or XML validators. Keep the service and DAO layer as-is; only the web tier changes.

Struts 1 to Struts 2 migration approach

1Run both side by side
add the Struts 2 filter alongside the Struts 1 servlet, split by URL
2Convert actions
Action + ActionForm become one POJO action with properties
3Rewrite config and views
struts-config.xml to struts.xml, Struts 1 tags to Struts 2 tags + OGNL
4Move validation and test
port validation, verify feature parity, then retire the old path

Keep the service and persistence layers untouched. Only the web tier is framework-specific, which is what makes incremental migration workable.

Key point: The production signal is 'incremental, side by side, feature by feature'. Proposing a big-bang rewrite of a large app is the answer that worries interviewers.

Q45. How does ActionInvocation drive the interceptor chain internally?

ActionInvocation holds the ordered list of interceptors, the action, and the result. Each interceptor's intercept() calls invocation.invoke(), which pops the next interceptor and calls it; when the list is exhausted, invoke() runs the action and captures the result name.

That recursion is the onion: every invoke() call nests one level deeper, and the after-code in each interceptor runs as the recursion unwinds. Returning a result name from an interceptor instead of calling invoke() short-circuits the whole chain, which is how auth interceptors block requests.

Q46. How do you write a custom result type, and when is it worth it?

Implement the Result interface (or extend StrutsResultSupport) and put your rendering logic in execute(ActionInvocation), then register the result type in a package. You get access to the action and value stack, so you can render anything: a CSV export, a PDF, a signed redirect, a templated email preview.

It's worth it when a rendering concern repeats across actions and doesn't fit dispatcher, stream, or json. Bundling it as a result type keeps the actions clean and the behavior reusable.

java
public class CsvResult extends StrutsResultSupport {
    protected void doExecute(String location, ActionInvocation inv)
            throws Exception {
        HttpServletResponse resp = ServletActionContext.getResponse();
        resp.setContentType("text/csv");
        Object data = inv.getStack().findValue(location);
        writeCsv(resp.getWriter(), data);
    }
}

Q47. How does the value stack resolve properties, and what are the performance implications?

The value stack is an OgnlValueStack wrapping a CompoundRoot, a list of objects searched top to bottom. Resolving an unqualified name walks each object looking for a matching property, so a deep stack means more objects to search per expression.

In practice OGNL reflection and stack searching are cheap next to I/O, but two things bite at scale: expressions evaluated in tight loops in a JSP, and very deep stacks from heavy action chaining or nested ModelDriven. Keeping the stack shallow and hoisting repeated OGNL lookups out of loops is the tuning that matters.

Q48. How do you unit test Struts 2 actions?

Because actions are POJOs, the core logic tests like any other object: construct the action, set its properties, call execute(), assert the returned result name and the resulting state. No container needed for that path, which is a real advantage over Struts 1.

For anything touching the framework (interceptors, the value stack, validation wiring), the struts2-junit-plugin provides StrutsTestCase, which spins up the Struts context so you can drive a full action through its interceptors and check results end to end.

java
@Test
void validInputSucceeds() {
    HelloAction action = new HelloAction();
    action.setName("Asha");
    assertEquals(Action.SUCCESS, action.execute());
    assertEquals("Asha", action.getName());
}

Key point: The point to make is testability by design: POJO actions test without a container, which is a headline Struts 2 improvement over Struts 1's servlet-bound Actions.

Q49. How do you approach performance tuning in a Struts 2 application?

Measure before you change anything: most Struts app latency is in the database and downstream calls, not the framework. Profile a realistic load and fix the biggest cost first, which is usually N+1 queries, missing caching, or slow service calls, not OGNL.

Framework-level levers once you've ruled out the obvious: turn off devMode in production, trim the interceptor stack to what each package needs, keep the value stack shallow, cache expensive lookups, and precompile JSPs. Enable OGNL and config caching that the framework already provides rather than fighting the framework.

Q50. How do you organize configuration across a large Struts 2 codebase?

Split struts.xml into per-module files with the include element, so each team or feature owns its own config file and the root just includes them. Combine that with namespaces so URL prefixes match module boundaries, and package inheritance so modules extend a shared base stack.

The convention plugin can remove much of the XML entirely by inferring mappings. The judgment call is consistency: pick XML, annotations, or convention as the team standard rather than mixing all three, because a half-XML half-annotated codebase is hard to reason about.

xml
<struts>
  <include file="struts-admin.xml"/>
  <include file="struts-billing.xml"/>
  <include file="struts-api.xml"/>
</struts>

Q51. How does type conversion work in Struts 2, and how do you customize it?

Struts converts string request parameters to action property types automatically: OGNL handles primitives, dates, and collections, converting form strings to ints, booleans, Dates, and List or Map properties. Conversion errors are collected and can route to the input result.

For custom types you write a TypeConverter (extending StrutsTypeConverter) and register it globally in xwork-conversion.properties or per property in a ClassName-conversion.properties file. That's how you bind, say, a comma-separated string to a domain object or a custom date format.

java
public class MoneyConverter extends StrutsTypeConverter {
    public Object convertFromString(Map ctx, String[] values, Class toType) {
        return Money.parse(values[0]);   // "12.50" -> Money
    }
    public String convertToString(Map ctx, Object o) {
        return ((Money) o).toDisplay();
    }
}

Q52. What is the difference between global and local results, and when do you use each?

A local result is declared inside an action and only that action can return it. A global result, declared once per package in global-results, is available to every action in the package, so you don't repeat common outcomes like error or login in every mapping.

Use locals for outcomes specific to one action (a particular success page), and globals for shared outcomes: a common error page, a login redirect, a not-found result. Globals pair naturally with global exception mappings.

Q53. How do you handle type conversion and validation errors together cleanly?

The conversionError interceptor turns failed conversions (a non-numeric age) into field errors, and the validation and workflow interceptors turn failed rules into field errors too. Both funnel to the input result, so the user sees one form with all their mistakes flagged.

The clean pattern is to let conversion errors and validation errors coexist: order the interceptors so conversionError runs, then validation, then workflow routes to input if either produced errors. Fighting this by catching conversion in the action is the messier path.

Q54. How do Struts 2 apps fit modern deployment, containers, and async work?

Struts 2 is a servlet-based framework, so it runs anywhere a servlet container does: Tomcat or Jetty in a Docker image, behind a load balancer, scaled horizontally like any stateless web app. Keep session state out of the app (externalize to Redis or a sticky-session-free design) and it scales fine.

For long-running or async work, don't block the request thread inside an action; hand the job to an executor or a queue and return quickly, or use the servlet container's async support at the filter layer. Struts itself is synchronous request-response, so heavy async patterns live around it, not inside the action.

Q55. What is XWork and how does it relate to Struts 2?

XWork is the command-and-interceptor framework Struts 2 was originally built on, inherited from WebWork. It provided the action invocation model, the interceptor chain, the value stack, OGNL integration, and validation, all independent of the web. Struts 2 layered the servlet-specific pieces (the filter, result types, tags) on top.

Over time XWork was absorbed into the Struts codebase, so you see it in package names and older docs. Knowing this explains why so much of Struts 2's core is web-agnostic and why actions test without a container.

Q56. How do Struts UI tag themes work, and how would you customize them?

Struts UI tags render through themes: the default xhtml theme wraps each field in a table row with a label and error slot, the simple theme renders just the raw input, and css_xhtml uses CSS instead of tables. You set the theme per tag, per form, or globally.

To customize, you copy the FreeMarker templates for a theme, edit the markup, and point Struts at your template directory, or write a new theme extending an existing one. Most teams switch to simple and control markup themselves rather than fight the table-based defaults.

Q57. How do ActionContext, ServletActionContext, and the value stack relate?

ActionContext is the framework-neutral, thread-local map holding the value stack, parameters, session, and locale for the current request; it's the abstraction actions should use. ServletActionContext extends it with servlet-specific access to the raw HttpServletRequest, HttpServletResponse, and ServletContext when you genuinely need them.

The value stack lives inside ActionContext and is the OGNL root. So the layering is: ActionContext is the bag, the value stack is one item in it, and ServletActionContext is the escape hatch to the servlet API. Preferring ActionContext keeps actions decoupled and testable.

Q58. When would you recommend against using Struts for a new project?

For most new Java web work, because the ecosystem has moved to Spring Boot and, for APIs, lighter stacks. Struts 2's strengths (structured MVC, interceptors, tag-driven forms) are well served by Spring MVC with a larger, more actively developed ecosystem and better integration with data, security, and cloud tooling.

Struts still makes sense when you're extending an existing Struts application, when a team's whole operational knowledge is Struts, or during a migration where consistency beats rewriting. The mature coverage names Struts as a maintenance and migration technology and reserves new-build recommendations for Spring or similar.

Key point: the question needs honesty and current context, not loyalty to whatever framework the role uses. Placing Struts accurately is the strongest answer.

Q59. How does Struts 2 decide configuration when XML, annotations, and defaults all apply?

Struts builds its configuration from several providers in order: default framework settings, struts-default.xml (the base package and interceptors), plugin configs, struts.xml and its includes, then annotation and convention-based config from the convention plugin. Later providers can override earlier ones, and struts.properties or struts.xml constants tune framework settings.

The practical rule when something surprises you: explicit struts.xml usually wins over convention defaults, and package inheritance means an action's effective interceptor stack is whatever its package resolves to. Tracing that resolution order is how you debug a mapping that isn't behaving.

Q60. How do you carry state across requests in a multi-step Struts 2 wizard?

Struts actions are per-request, so a multi-step flow needs somewhere to hold partial state between steps. The straightforward option is the session: store the in-progress object under a key and load it at the start of each step, clearing it when the wizard finishes or is abandoned.

For cleaner scoping, the scopedModelDriven interceptor (or a token-based approach) ties a model to a conversation so parallel wizards in different tabs don't stomp each other. Pair that with the token interceptor to block double submits. The trade-off to name is session memory growth, so you evict abandoned conversations.

java
public class WizardAction extends ActionSupport implements SessionAware {
    private Map<String, Object> session;
    public void setSession(Map<String, Object> s) { this.session = s; }
    private Order draft;
    public void prepare() {
        draft = (Order) session.getOrDefault("wizard.order", new Order());
    }
    public String step2() {
        session.put("wizard.order", draft);   // persist between steps
        return SUCCESS;
    }
}

Key point: the question needs the state-location decision (session vs conversation scope) plus the double-submit guard (token interceptor) plus the cleanup concern. Naming all three indicates production experience.

Back to question list

Struts 1 vs Struts 2 vs Spring MVC

Struts 2 is not an upgrade of Struts 1; it's a different framework that kept the name. Struts 1 tied you to a servlet-aware Action base class and ActionForm beans. Struts 2 actions are plain objects with no framework base class required, tested without a container, and wired through interceptors instead of hardcoded controller logic. Spring MVC is the framework most teams pick for new work today, so knowing where each fits, and being honest that Struts is mostly a maintenance and migration skill now, indicates current rather than dated.

AspectStruts 1Struts 2Spring MVC
Action modelExtend Action, one instance sharedPOJO action, new instance per requestAnnotated @Controller methods
Form dataSeparate ActionForm beanProperties on the action itselfCommand objects / @ModelAttribute
Controller wiringstruts-config.xmlInterceptor stack + struts.xml/annotationsDispatcherServlet + annotations
Expression languageJSTL / ELOGNL + value stackSpEL / EL
StatusEnd of life (2013)Maintained, mostly legacy appsActively developed, common default

How to Prepare for a Struts Interview

Prepare in layers, and practice out loud. Most Struts rounds move from concept questions about MVC and the request lifecycle to reading or writing action and configuration code, then a discussion of interceptors, validation, or a migration. Rehearse each stage rather than only reading answers.

  • Master your tier's concepts until you can explain the request lifecycle without notes, then read one tier up for the stretch questions.
  • Set up a tiny Struts 2 app so you can point to a real struts.xml, an action, and a JSP result instead of describing them from memory.
  • Practice thinking aloud on small problems with a timer, because your process, not just the final answer is the technical point.
  • Take the quiz on this page to find weak spots, then revisit those questions before the real round.

The typical Struts interview flow

1Recruiter or phone screen
background, Java web experience, a few concept checks
2Core concepts
MVC roles, request lifecycle, interceptors, OGNL and the value stack
3Code and config
write or read an action, struts.xml mapping, and a JSP result
4Design or migration
Struts 1 to 2 migration, security patching, trade-offs and follow-ups

Earlier rounds increasingly run as AI coding interviews. The concepts on this page are what gets probed at every stage.

Test Yourself: Struts Quiz

Ready to test your Struts knowledge?

10 questions, about 6 minutes. Score 70% or higher to earn a shareable certificate.

10 questions Instant feedback Free certificate on 70%+

Frequently  Asked  Questions

Which Struts topics should I prioritize before a technical round?

Prioritize the areas that change real decisions: fundamentals, practical tasks, debugging, trade-offs, and evidence. The highest-value questions are tied to a project example, a validation check, or a failure mode.

Does Struts mean Struts 1 or Struts 2 in interviews?

Almost always Struts 2. Struts 1 reached end of life in 2013 and no interviewer expects new code on it. If a role touches Struts 1 at all, it's a maintenance or migration job, and the migration path is itself a common question. When in doubt, say you're answering for Struts 2 and note the Struts 1 difference where it matters.

Are these questions enough to pass a Struts interview?

They cover the question-answer portion well, but many backend rounds also include live coding: writing an action, wiring struts.xml, or reading unfamiliar code while explaining your thinking. building a small app and talking through the request lifecycle is the practice path. Our AI coding interview prep guide covers that format, including how automated evaluation reads your process.

How long does it take to prepare for a Struts interview?

If you've shipped Struts code before, one to two weeks of an hour a day refreshes the lifecycle, interceptors, and OGNL with practice runs. Starting colder, plan three to four weeks and build a small app daily; reading answers without wiring a real action is how preparation quietly fails.

Do interviewers ask exactly these questions?

The concepts repeat far more reliably than the exact wording. Interviewers rephrase, chain follow-ups, and push toward whatever you claim confidence in. Prepare the underlying ideas, MVC roles, the request lifecycle, interceptors, OGNL, and validation, and the phrasing takes care of itself.

Is there a way to test my Struts knowledge?

Yes. The quiz on this page scores you as you go and explains every answer, so you find your weak spots fast. Pass the threshold and you can download a shareable certificate with your name and score, free and with no sign-up. It's the quickest way to check yourself before the real round.

From the team that builds coding interviews

Hyring builds the AI Coding Interviewer that runs live technical rounds in 20+ languages for 5,000+ hiring teams. These Struts questions and scoring notes reflect what actually gets asked and evaluated inside the interviews we host.

See how the AI Coding Interviewer works

Sources

Adithyan RKWritten by Adithyan RK
Surya N
Fact-checked by Surya N
Published on: 3 Apr 2026Last updated: 10 Jul 2026
Share: