Skip to content
PYD ENTERPRISES

Migration guide

COBOL to Java Spring Boot: extract the spec before you write the service

Spring Boot teams fail on COBOL when they port paragraphs instead of rules. This guide shows how to turn copybooks, COMP-3 fields and PERFORM chains into contracts a Java team can build against.

COBOLJava Spring Boot
DIFFICULTY
High
OUTPUT
Rule / schema JSON
SYNTAX TRAPS
5 covered
WORKFLOW
6 steps

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

Technical syntax challenges

Where COBOL migrations go wrong.

01

COMP-3 packed decimal and implied scale

PIC S9(9)V99 COMP-3 occupies 6 bytes ((11 + 1) / 2) and carries an implied decimal point that never appears in the data. In Java it must become BigDecimal with scale 2 and an explicit RoundingMode; mapping it to double silently loses cents in accrual loops.

02

ROUNDED versus truncation

COBOL truncates intermediate results to the receiving field unless the statement says ROUNDED, and the default ROUNDED mode is half-up (away from zero). A Java port that calls setScale(2, RoundingMode.HALF_EVEN) everywhere disagrees with production on a measurable share of postings.

03

88-level condition names hide the domain vocabulary

88 ACCT-DORMANT VALUE 'D' 'X'. means one business state maps to two stored codes. The rule extractor must carry both values into the enum or decision table, otherwise the Java service rejects historical records written with the older code.

04

PERFORM THRU and fall-through paragraphs

PERFORM 2000-CALC THRU 2999-EXIT executes every paragraph between the two labels in source order, including any added later by maintenance. The real call graph only exists after the control-flow graph is built across the THRU range.

05

Copybook REDEFINES as type unions

A record that redefines the same 40 bytes as a personal or a business layout is a discriminated union. Java needs a sealed interface or two record types selected by the discriminator field, not one class with every field nullable.

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

    Export sources with their copybook libraries

    Export the COBOL members, every COPYLIB in the concatenation order your compile JCL uses, and the DB2 DDL. Concatenation order matters when two libraries hold a copybook with the same name.

  2. 2

    Parse to AST and resolve storage layouts

    PYD ENTERPRISES parses each program with the IBM Enterprise COBOL dialect, expands copybooks with REPLACING, and computes the byte offset, length and usage of every data item, including REDEFINES variants.

  3. 3

    Build the cross-program call and control-flow graph

    Static CALLs, CICS LINK and XCTL targets and PERFORM THRU ranges are resolved into one graph, so dead paragraphs and fall-through paths are visible before any rule is named.

  4. 4

    Separate business rules from plumbing

    Program slicing on each output field isolates the statements that compute business values. File status checks, DISPLAY tracing and abend handling are classified as plumbing and listed separately.

  5. 5

    Export DMN tables, JSON Schema and OpenAPI

    Decisions become DMN 1.5 tables with FEEL expressions, records become JSON Schema 2020-12 with decimal constraints, and program entry points become OpenAPI 3.1 operations, each linked to file and line range.

  6. 6

    Generate equivalence fixtures for the Spring team

    Boundary fixtures are generated from real branch conditions (for example balance 1499.99 and 1500.00). The Java team runs them against the new service in CI until every fixture matches the legacy result.

Legacy in, specification out

The source, and what PYD ENTERPRISES extracts from it.

Left: the COBOL construct as it sits in production. Right: the reviewed artifact your Java Spring Boot engineers build against. PYD ENTERPRISES produces the spec and the tests; your team writes the service.

LEGACY SOURCE

LNACCR02.cbl (lines 1187 to 1204)COBOL
1 01 LN-ACCRUAL-AREA.
2 05 LN-PRIN-BAL PIC S9(9)V99 COMP-3.
3 05 LN-ANN-RATE PIC S9(3)V9(6) COMP-3.
4 05 LN-DAILY-INT PIC S9(7)V99 COMP-3.
5 05 LN-BASIS-CODE PIC X(01).
6 88 BASIS-360 VALUE '0'.
7 88 BASIS-365 VALUE '5' '6'.
8 *
9 2100-CALC-DAILY-INT.
10 IF BASIS-360
11 COMPUTE LN-DAILY-INT ROUNDED =
12 LN-PRIN-BAL * LN-ANN-RATE / 360
13 ELSE
14 COMPUTE LN-DAILY-INT ROUNDED =
15 LN-PRIN-BAL * LN-ANN-RATE / 365
16 END-IF.
17 2100-EXIT.
18 EXIT.

EXTRACTED ARTIFACT

LNACCR-0412.rule.jsonJSON
1{
2 "id": "LNACCR-0412",
3 "name": "Daily interest accrual by day-count basis",
4 "hitPolicy": "UNIQUE",
5 "inputs": [
6 { "name": "basisCode", "type": "string", "source": "LN-BASIS-CODE" }
7 ],
8 "outputs": [
9 { "name": "dailyInterest", "type": "decimal", "scale": 2, "rounding": "HALF_UP" }
10 ],
11 "rules": [
12 { "when": ["\"0\""], "then": ["principal * annualRate / 360"] },
13 { "when": ["\"5\", \"6\""], "then": ["principal * annualRate / 365"] },
14 { "when": ["-"], "then": ["principal * annualRate / 365"], "note": "ELSE branch: any other code" }
15 ],
16 "types": {
17 "principal": "decimal(11,2) from S9(9)V99 COMP-3, 6 bytes",
18 "annualRate": "decimal(9,6) from S9(3)V9(6) COMP-3, 5 bytes"
19 },
20 "source": "LNACCR02.cbl:1187-1204"
21}

Architectural best practices

Build the Java Spring Boot side to the spec, not to the old shape.

  • Map every COMP-3 field to BigDecimal with the scale from its PIC clause and set RoundingMode.HALF_UP only where the COBOL statement says ROUNDED.
  • Model REDEFINES variants as sealed interfaces or separate records chosen by the discriminator, never as one class of nullable fields.
  • Keep the ELSE branch of every extracted decision visible: legacy code frequently charges or accepts values nobody intended, and the business must decide whether to keep that behavior.
  • Design Spring services around extracted decisions and data contracts, not around COBOL program boundaries; one program often contains three bounded contexts.
  • Run the generated equivalence fixtures in the same CI pipeline as unit tests so drift is caught on every commit, not at cutover.

Why line-by-line translation fails on Spring Boot

A transpiled Spring service keeps the COBOL shape: one class per program, fields named WS-TEMP-AMT-2, and control flow driven by flags set three paragraphs earlier. It compiles, it passes a smoke test, and nobody on the Java team can change it safely. The faster route is to agree what the program does first.

PYD ENTERPRISES does not write the Spring application. It produces the decision tables, JSON Schemas, OpenAPI operations and fixtures that describe the legacy behavior, each traceable to source lines, so your engineers write idiomatic services and prove they match. Analysts review every extracted rule beside the COBOL that produced it before it reaches a backlog.

Handling numeric precision end to end

Precision bugs are the most common post-cutover defect in COBOL to Java programs. The storage layout tells you the declared precision, but the arithmetic tells you the effective precision: COBOL computes intermediates with enough digits for the operands and then truncates or rounds into the receiver.

  • Declared type: S9(7)V99 COMP-3 becomes decimal(9,2), carried in JSON Schema as a string with a pattern or as a number with multipleOf: 0.01.
  • Operation order: COMPUTE A = B * C / D multiplies first, so the Java expression must not divide first.
  • Receiver behavior: without ROUNDED, extra digits are truncated toward zero, which is RoundingMode.DOWN in Java.

FAQ

COBOL to Java Spring Boot questions

Does PYD ENTERPRISES convert COBOL to Java code?

No. PYD ENTERPRISES extracts specifications: business rules as DMN 1.5, data contracts as JSON Schema, interfaces as OpenAPI 3.1 and behavioral fixtures. Your engineers write the Spring Boot services and use the fixtures to prove equivalence.

How are COMP-3 fields represented in the exported contracts?

Each packed field keeps its total digits and scale from the PIC clause. JSON Schema exports carry them as decimal strings or numbers with multipleOf constraints, and the rule metadata records the original usage and byte length so Java teams pick BigDecimal with the right scale.

What happens to code PYD ENTERPRISES cannot classify?

Every executable path is accounted for: extracted as a rule, classified as plumbing, or flagged for review. Flagged paths, such as dynamic CALL targets built at runtime, appear in the review queue with their source lines.

Get the spec for your COBOL estate.

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