RPG to Java: move the business logic off IBM i and onto the JVM.
Your RPG runs the company and you cannot change it any more. We read it with a language engine built for RPG IV and DDS, and we translate it into Java your own developers will accept as theirs — incrementally, while the IBM i keeps running.
Figures for the RPG & DDS Language Engine, the parser every RPG project of ours starts from. Its regression corpus is 53 open-source RPG repositories, roughly 3,000 files and 540,000 lines, re-run on every change.
Many companies built their whole operation on RPG, and two industries dominate the population: manufacturing, where the code runs warehouse management, order processing and production control, and financial services, where it runs accounting and customer records. The system still works. What it no longer gives you is room to change: every modification is slow, every integration is a special case, and the people who know the code are retiring.
Talk to us if you need help with your RPG-to-Java migration. We have done this work many times, and we know which parts are mechanical and which parts are where projects quietly go wrong.
What your RPG becomes
The clearest way to answer “what will my code look like afterwards?” is to show a translation you can run yourself. Below is a subroutine from an RPG program and the Java method produced from it. Both files are in a public repository; the Java compiles under any JDK and prints the right answer.
Input — fixed-format RPG
C FIB BEGSR
C SELECT
C WHEN NBR = 0
C EVAL RESULT = 0
C WHEN NBR = 1
C EVAL RESULT = 1
C OTHER
C FOR COUNT = 2 TO NBR
C EVAL RESULT = A + B
C EVAL A = B
C EVAL B = RESULT
C ENDFOR
C ENDSL
C ENDSROutput — Java
void FIB() {
if (this.NBR == 1) {
this.RESULT = 1;
} else {
for (this.COUNT = 2;
this.COUNT <= this.NBR;
this.COUNT++) {
this.RESULT = this.A + this.B;
this.A = this.B;
this.B = this.RESULT;
}
}
}javac CalcFib.java && java CalcFib prints FIBONACCI OF: 20 IS: 6765.Both files come from Strumenta/rpg-to-java-transpiler, which we publish as a teaching example alongside the tutorial How to write a transpiler. It is not the tooling we run on client work, and it is deliberately small. We publish it so you can read a complete RPG-to-Java pipeline end to end instead of taking our word for the shape of the output. The for statement is wrapped here for the page; the file itself keeps it on one line.
What we read before anything is translated
Automated translation is only as good as the reading that precedes it. RPG applications are never just RPG: they are fixed-form and free-form RPGLE, embedded SQL in SQLRPGLE, and the DDS files that define the data. Our engine reads all of it and resolves the references across the whole codebase, so a field used in a calculation spec links back to the DDS record format or DB2 column that declares it.
| Source | Status | Detail |
|---|---|---|
| RPG IV (ILE RPG), fixed-column | Supported | Including all 13 compiler directives |
| RPG IV free format (**FREE, /FREE) | Supported | Same model as the fixed-column form |
| SQLRPGLE | Supported | EXEC SQL parsed by a dedicated DB2 parser |
| DDS | Supported | Physical, logical, display and printer files |
| Synon / CA 2E generated RPG | Supported | Lifted to the 2E function view |
| RPG III | Supported | Adapted to the RPG IV fixed layout, same AST |
| RPG II | Not supported | Tell us early if your estate contains it |
RPG III is handled by conversion, not by a second parser. An RPG III member is adapted line by line into the equivalent RPG IV fixed layout and then goes through the same pipeline as everything else. That matters more than it sounds: both produce the same AST node types, so one set of tools, one set of migration rules and one set of tests covers a mixed RPG III and RPG IV estate. You do not get two half-migrations that have to be reconciled later.
Three places an RPG-to-Java translation quietly goes wrong
Syntax is the solvable part. What separates a translation that compiles from a translation that behaves the same is the semantic layer underneath, and there are three constructs where the difference shows up in production rather than in tests.
- Indicators are global state, not local booleans. RPG gives a program 99 general-purpose indicators plus the special ones — LR, MR, the control-level and halt families. They are not scoped to a call: unless
*INLRis set on, a program that returns keeps every indicator at the value it was left at, and the next call sees it. Translating each*INxxinto an isolated Java boolean produces code that passes unit tests, which instantiate the class fresh, and diverges the moment the program is called twice in the same activation group. The translation has to follow the data flow, find every operation that sets an indicator, and emit named state accordingly. - Data structure overlays are a memory layout, not a class. Subfields sitting at the same offset can be packed decimal, zoned decimal, character or binary at the same time, depending on which name you read them through. The translation has to carry an explicit layout model and generate accessors for each logical field. Emitting a byte array would be semantically faithful and unmaintainable, which defeats the purpose of moving to Java at all.
- Packed decimal arithmetic does not survive a naive port. RPG truncates by default when a result has more decimal places than its target, and
EVAL(H)half-adjusts away from zero. Java has no default rounding mode at all:BigDecimalthrowsArithmeticExceptionrather than guess. Every arithmetic operation that can hit a rounding boundary needs a runtime support library and a generated call into it. Teams that skip this ship code that agrees with the old system on almost every row, and disagrees on money.
A parser that is ninety-five per cent right is worthless. So is a translation that is right on ninety-five per cent of the arithmetic.
Why Java rather than Python
The choice is not a matter of developer taste, it is a question about how long the migrated system has to live. Java is the right target when the system must outlast the team that builds it and when types have to be checked before the code runs — which is the normal situation in banking, insurance and anywhere an auditor will eventually ask why a number is what it is. Python is the better answer when the migrated system is a stepping stone to something else, or when the destination is data work and a Python-first team.
Two market facts are worth knowing while you decide. Fortra’s 2025 IBM i Marketplace Survey found that 54% of organizations report difficulty finding RPG or COBOL developers, and that 78% of IBM i users named modernization their top IT priority in 2025, up from 65% the year before. Both languages solve the hiring problem; only one of them is already the second language on your own platform.
If Python is your destination, we have a packaged route for it: see RPG to Python.
How the work is packaged
Migration Blueprint
We read the codebase before anyone commits to anything, and produce the plan, the risks, the mapping definition, the testing strategy and a fixed price.
Migration CodeCraft
The migration itself. Java in your architecture, delivered module by module, verified against the behavior of the original. You own the migrated code outright.
The engine on its own
If you want to do the analysis yourself, the RPG & DDS Language Engine is licensable as a JVM library, a command-line tool or an HTTP service.
What we can show you, and what we cannot
- We have not published an RPG-to-Java case study. Our published RPG migration case study targets Python, not Java: David Nieper. We would rather tell you that than dress up a Java reference we cannot name.
- The engine is public enough to check. The coverage above is what the parser handles, the test and corpus figures are the ones we run in CI, and the RPG-to-Java pipeline architecture is readable in a repository you can clone.
- Open foundations, no lock-in. Our AST framework, Starlasu, is Apache-2.0 and public, with implementations for Kotlin, Python, TypeScript and C#. There is no proprietary intermediate representation holding your codebase hostage.
- You own what we write. Under Migration CodeCraft the migrated code is yours in full. We keep ownership of the runtime library, but you get its source and a license to use it however you want, with no recurring fee and no obligation to keep us for support.
Get the book
Migrating RPG Code to Modern Languages collects what we have learned doing this work: how to plan a migration, what is worth automating, and where projects go wrong.
Tell us what your RPG estate looks like.
How much code, which flavours, how much of it is Synon-generated, what it runs. We will tell you honestly what an RPG-to-Java migration would take — including when the honest answer is that it is not worth starting yet.