At some point, every developer faces what looks like a “simple fix.”
This one started exactly like that. It was supposed to be a small improvement:
“We need to make sure CPF and CNPJ are saved without formatting.”
Sounds easy, right? A couple of replaceAll() calls, maybe a quick algorithm… done.
But as I’ve learned (and re-learned many times), in enterprise systems — especially in Oracle PSRM — nothing is ever just string manipulation.
Understanding the IDs Behind the Problem
Before diving deeper, it’s important to understand what these identifiers represent — especially if you’re not familiar with Brazilian systems.
CPF (Cadastro de Pessoas Físicas)
The CPF is a Brazilian individual taxpayer identification number issued by the Federal Revenue Service.
- Assigned to individual persons
- Used in banking, legal contracts, and tax reporting
- Exemple format:
999.999.999-99
You can think of CPF as similar to the Social Security Number (SSN) in the United States.
CNPJ (Cadastro Nacional da Pessoa Jurídica)
The CNPJ is the identification number for legal entities (companies) in Brazil.
- Assigned to businesses and organizations
- Used for tax registration, billing, and legal operations
- Exemple format:
99.999.999/9999-99
Conceptually, it is similar to an Employer Identification Number (EIN).
Passport
A passport is an internationally recognized identification document issued by a government.
- Used mainly for foreign individuals without CPF
- Alphanumeric format (varies by country)
- Example format:
AB999999
Why This Matters
Although these identifiers serve different purposes, they all share one key role:
They act as unique identity keys across enterprise systems
And that’s exactly where the real problem begins — inconsistent formatting.
Where Things Started to Feel Off
The initial implementation worked perfectly.
For CPF, I tested:
999.999.999-99 → 99999999999 ✅
All good. Deployed to homologation. Confidence high.
Then came the first sign that something wasn’t right.
For CNPJ:
99.999.999/9999-99 → still stored with formatting ❌
Same logic. Same code. Different result.
That’s when I knew this wasn’t a “regex problem.”
The Moment of Realization
In enterprise systems, especially OUAF-based ones, there’s a hidden layer that many developers underestimate:
The Business Object structure defines behavior more than your code does.
So instead of continuing to tweak the algorithm, I shifted focus to the execution context. And that’s where everything clicked.
Two “Persons”, Two Different Worlds
Even though the system talks about “Person” as a single entity, internally it’s not that simple.
There are different Business Objects handling different flows:
C1-PersonIndividual→ used for CPFC1-PersonLegalEntity→ used for CNPJ
Same concept, completely different pipelines. And guess what?
My algorithm was only attached to one of them.
Why This Was Subtle (and Dangerous)
This type of issue is tricky because:
- Everything seems to work
- Tests pass for one scenario
- There are no errors in logs
- The behavior is just… inconsistent
In reality, the system was doing exactly what it was configured to do.
I just hadn’t mapped the full picture.
The Fix Was Simple — After Understanding the Problem
Once I identified the root cause, the fix became obvious:
- Create a reusable normalization algorithm
- Attach it to both Business Objects:
- ✅ Individual
- ✅ Legal Entity
And most importantly:
👉 Run it during Pre-Processing
That guarantees:
- Execution before persistence
- Consistency across UI, integrations, and batch processes
The Final Algorithm
@Override
public void invoke() {
if (boInstance == null) {
return;
}
COTSInstanceList idList = boInstance.getList(Elements.PERSON_ID_LIST);
if (idList != null) {
for (COTSInstanceListNode node : idList) {
String idNumber = node.getString(Elements.PERSON_ID_NUMBER);
if (idNumber == null || idNumber.trim().isEmpty()) {
continue;
}
String idType = node.getString(Elements.ID_TYPE);
String normalized;
if (IdTypes.CPF.equals(idType)) {
normalized = idNumber.replaceAll("[^0-9]", "");
} else {
normalized = idNumber.replaceAll("[^a-zA-Z0-9]", "");
}
node.set(Elements.PERSON_ID_NUMBER, normalized);
}
}
}
Nothing fancy. But in the right place — it solves a real problem.
What This Really Taught Me
This wasn’t about CPF, CNPJ, Passport or regex. It was about understanding the system.
🔹 1. Context Matters More Than Code
You can write clean, correct logic…
…but if it runs in the wrong Business Object, it won’t work.
🔹 2. “It Works” Can Be Misleading
A fix that works for one flow doesn’t mean the problem is solved. Always validate:
- All entity types
- All entry points
- All integration paths
🔹 3. Normalize Data Close to Persistence
Trying to fix formatting in UI or services is fragile. Doing it at the BO level:
✅ Centralizes logic
✅ Prevents bypass
✅ Guarantees consistency
🔹 4. Small Problems Can Scale Quickly
What starts as formatting inconsistency can lead to:
- Duplicate records
- Integration failures
- Broken matching logic
All because of punctuation.
Final Result
After the fix:
✅ CPF stored without formatting
✅ CNPJ stored without special characters
✅ Passport handled correctly
✅ Consistent data across all flows
Closing Thought
This problem wasn’t really about formatting. It was about understanding how the system behaves under the hood.
And honestly? That’s what makes working with enterprise systems both frustrating — and interesting.
If You Work with Oracle PSRM / OUAF
Next time something “simple” doesn’t behave as expected…
👉 Don’t just debug your code
👉 Debug the execution context
That’s usually where the real answer is.

Leave a Comment