A Tiny Regex Bug in Adyen's Java Library, and How My Fix Shipped in SDK v42.0.0
In my last posts I wrote about why I started open source and about my first merged PR in Zalando Logbook. This one is about a PR in the Adyen Java API Library, and it is a good example of how a very small bug can hide in
In my last posts I wrote about why I started open source and about my first merged PR in Zalando Logbook. This one is about a PR in the Adyen Java API Library, and it is a good example of how a very small bug can hide in plain sight.
What is the Adyen Java library?
Adyen is a global payments company, and this library is how Java applications talk to Adyen's APIs. The whole SDK has to build the correct base URL for every service, for both test and live environments. If that URL is wrong, the payment call goes to the wrong place.
The bug
The method createBaseURL in Service.java swaps test URLs for live URLs. It used String.replaceFirst() to do that.
Here is the catch: replaceFirst() takes a regex, not a plain string. In regex, a dot . means "any character". So a URL part like pal-test.adyen.com was not matching a literal dot. It was matching any character in that position.
Simplified, it looked like this:
// Before: the dots are treated as "any character" because this is a regex
url = url.replaceFirst("pal-test.adyen.com", "pal-live.adyen.com");
For normal URLs it worked fine, which is exactly why nobody noticed. But a URL that only looks similar, with other characters where the dots should be, could still be transformed by mistake.
The fix
The fix was small. I replaced the affected replaceFirst() calls with String.replace(), which matches plain text with no regex at all:
// After: plain literal matching, no regex wildcard risk
url = url.replace("pal-test.adyen.com", "pal-live.adyen.com");
I updated the pal-, checkout- and device-api- blocks. I left the two calls without dots (-live to -test and back) as replaceFirst() on purpose, because they were not affected by this issue.
I also added a test, testLivePalUrlOnlyMatchesLiteralDots(), using a URL shaped like pal-testXadyenYcom. It looks like the real endpoint but has no literal dots, so it must not be transformed. The test proves the fix and protects against the bug coming back.
What the review taught me
-
Keep the scope tight. The maintainer said he thought about asking me to use
.replacein the other places in the method for consistency. Then he decided it was not necessary, because it was unclear whether that would cause some other issue. A good reviewer is careful about changes that were not asked for. It reminded me to fix the bug I was given, not everything I could. -
Formatting is part of the PR. The project had recently enforced code formatting, and my PR was blocked until I ran
mvn spotless:apply. A tiny thing, but it taught me to run the project's formatter and checks before pushing, every time. - Tests are the real proof. My first version of the test was not strong enough, and I improved it so the URL structurally matched the real one with non-dot separators. A test should fail without your fix, otherwise it proves nothing.
The PR was approved and merged, and the change shipped in SDK v42.0.0. Seeing something I wrote inside a release of a payments SDK was a good feeling. The change was small, but real people who use the library get it.
What I would tell someone starting out
- Small bugs are good first PRs. You do not need a big feature to make a real contribution.
- Read the project's contributing rules and run its formatter and tests before you push.
- Write a test that fails without your fix.
- Do not widen the scope. Fix what the issue asks for.
Proof of my work
Everything here is public, so you can check it yourself:
- Adyen/adyen-java-api-library #1952: the regex fix (merged, shipped in v42.0.0)
- The original issue #1838
- zalando/logbook #2301: StatusCodeBasedSink and LevelBasedHttpLogWriter (merged)
- PicnicSupermarket/error-prone-support #2275: merged after review
- Sionna Visualizer: my side project, a 6G + AI dashboard (live demo)
- My GitHub: all my repos and contributions
Next post: my PR in Picnic's error-prone-support, and what working with a strict reviewer taught me.
If you are a maintainer, a recruiter or a team looking for someone who learns in public and likes to collaborate, my DMs are open. Tell me in the comments if you have hit a regex surprise like this one.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.