Skip to content
PYD ENTERPRISES

Migration guide

Struts to React and FastAPI: move validation from ActionForms into API schemas

Struts apps spread one screen's behavior across struts-config.xml, validation.xml, an ActionForm and an Action. This guide shows how to reassemble it into an API contract and a rule set.

Apache StrutsReact + FastAPI
DIFFICULTY
Moderate
OUTPUT
OpenAPI / YAML
SYNTAX TRAPS
5 covered
WORKFLOW
6 steps

By Pranav Kulkarni, Head of Language Engineering · Updated 15 Oct 2026

Technical syntax challenges

Where Apache Struts migrations go wrong.

01

Validation split across three places

Commons Validator rules in validation.xml (required, mask, intRange, date), the ActionForm's own validate() method and checks inside Action.execute() all reject input. The API schema has to hold the union of all three, or the new FastAPI endpoint accepts data the old screen refused.

02

ActionForm properties are strings

Struts 1 ActionForms usually declare every property as String so invalid input can be redisplayed. The real type (decimal, date, enum) is implied by the validator rules and by parsing code in the Action, which is where the extractor reads it from.

03

Navigation lives in action mappings

<action path="/submitClaim" ... input="/claim.jsp"> with <forward name="review"> defines the flow. Forward names returned by mapping.findForward() are outcomes of a decision and map to API responses or React routes.

04

DispatchAction and session-scoped forms

DispatchAction picks a method from a request parameter, so one action path is several operations. Forms in scope="session" carry state across pages, a multi-step wizard that the React app must model explicitly.

05

Struts 2 interceptors and OGNL

In Struts 2, interceptor stacks run validation, file upload and authorization before an action; OGNL expressions in JSPs and validation.xml files can contain logic. Both have to be read to know what an action really accepts.

Extraction workflow

6 steps from source to signed-off spec.

The sequence a PYD ENTERPRISES Discovery Scan runs for this stack. Every output links back to source file and line range.

  1. 1

    Ingest WAR source with Struts configuration

    Include struts-config.xml or struts.xml, every validation.xml and validator-rules.xml, JSPs, Tiles definitions and the Java source for forms and actions.

  2. 2

    Resolve action mappings to code

    PYD ENTERPRISES links each action path to its Action class, form bean, input page and forwards, including DispatchAction methods selected by parameter.

  3. 3

    Merge declarative and programmatic validation

    Validator rules, validate() methods and checks in execute() are merged per form field into one constraint set with source links.

  4. 4

    Infer real types from parsing and rules

    String properties parsed with new BigDecimal() or SimpleDateFormat and constrained by double or date validators get their real types and formats in the schema.

  5. 5

    Extract business rules from Actions and services

    Logic that decides forwards or computes values is sliced out of execute() and called services, then emitted as DMN tables.

  6. 6

    Export OpenAPI 3.1 and screen flow

    Each operation becomes an OpenAPI path with a JSON Schema request body; forwards and session forms become a flow diagram for the React team.

Legacy in, specification out

The source, and what PYD ENTERPRISES extracts from it.

Left: the Apache Struts construct as it sits in production. Right: the reviewed artifact your React + FastAPI engineers build against. PYD ENTERPRISES produces the spec and the tests; your team writes the service.

LEGACY SOURCE

validation.xml (claimForm)XML
1<form name="claimForm">
2 <field property="policyNumber" depends="required,mask">
3 <var>
4 <var-name>mask</var-name>
5 <var-value>^[A-Z]{2}[0-9]{8}$</var-value>
6 </var>
7 </field>
8 <field property="lossAmount" depends="required,double,doubleRange">
9 <var><var-name>min</var-name><var-value>0.01</var-value></var>
10 <var><var-name>max</var-name><var-value>250000</var-value></var>
11 </field>
12 <field property="lossDate" depends="required,date">
13 <var>
14 <var-name>datePatternStrict</var-name>
15 <var-value>MM/dd/yyyy</var-value>
16 </var>
17 </field>
18</form>
19<!-- ClaimForm.validate(): lossDate must not be after today -->

EXTRACTED ARTIFACT

claims.openapi.yamlYAML
1components:
2 schemas:
3 ClaimSubmission:
4 type: object
5 x-pyd-source:
6 - validation.xml:12-29
7 - ClaimForm.java:58-66
8 required: [policyNumber, lossAmount, lossDate]
9 properties:
10 policyNumber:
11 type: string
12 pattern: "^[A-Z]{2}[0-9]{8}$"
13 lossAmount:
14 type: number
15 minimum: 0.01
16 maximum: 250000
17 lossDate:
18 type: string
19 format: date
20 description: Legacy input MM/dd/yyyy; must not be in the future
21 x-pyd-rule: CLAIM-VAL-03

Architectural best practices

Build the React + FastAPI side to the spec, not to the old shape.

  • Make the API schema the single place validation lives; let React derive client-side checks from it rather than re-typing rules.
  • Pydantic models in FastAPI generate OpenAPI, so check the generated document against the extracted one in CI to catch drift.
  • Convert legacy display formats like MM/dd/yyyy at the UI edge and keep ISO 8601 in the contract.
  • Model session-scoped wizard forms as explicit draft resources with their own endpoints instead of server session state.
  • Keep forward names as documented outcomes in the spec; they are often the clearest statement of what a business decision returns.

Why Struts is a good first migration

Of the Java EE stacks, Struts applications are often the most tractable: the configuration files are an index of every screen, every operation and most validation. The difficulty is not finding logic but reassembling it, because one user action touches four files. That is mechanical work PYD ENTERPRISES does well, which is why Struts estates usually reach a reviewed contract quickly.

The outputs are an OpenAPI 3.1 document per functional area, DMN tables for decisions found in Actions and services, and a screen-flow diagram from action mappings. Your React and FastAPI engineers build against those. PYD ENTERPRISES does not generate React components or Python endpoints.

Security fixes are not rules

Struts 1 reached end of life in 2013 and Struts 2 has had serious remote code execution vulnerabilities, so many estates carry workarounds: servlet filters that strip parameters, custom interceptors, regex blocklists. PYD ENTERPRISES classifies these as plumbing, not business rules, and lists them separately. They should inform the security review of the new stack, but they should not be rebuilt as features of the FastAPI service.

FAQ

Apache Struts to React + FastAPI questions

Does PYD ENTERPRISES support both Struts 1 and Struts 2?

Yes. Struts 1 struts-config.xml and Commons Validator files, and Struts 2 struts.xml, action-level validation XML, annotations and interceptor stacks are all parsed and linked to the Java source.

Will the generated schema match what FastAPI produces?

The extracted schema is JSON Schema 2020-12 inside OpenAPI 3.1, which FastAPI also emits. Teams usually write Pydantic models to match it and diff the generated document against the extracted one in CI.

What happens to logic inside JSP scriptlets?

Scriptlets and JSTL expressions are parsed. Conditional display logic is classified as presentation; calculations and decisions found there are extracted as rules and flagged so the team can move them server side.

Get the spec for your Apache Struts estate.

Request a codebase scan and review extracted rules, contracts and fixtures for your own Apache Struts estate, inside your VPC.