When Fixing a Mistake Takes Five Years: the HttpMethod enum
08 May 2025One of the differences between working on a library or framework and building an application is what Dan North has called the Change Event Horizon: the amount of time it takes to undo a mistake.
In an internally deployed application, the horizon is short—you can fix a mistake in the next release. But in a library or framework, especially one as widely used as Spring, the horizon stretches much further. Mistakes can linger for years.
That is because every feature—no matter how flawed—is used in someone’s codebase. Fixing it means breaking backward compatibility. Unless the issue is critical, such as a security vulnerability, breaking user code is usually off the table.
Even when users agree with the change in principle, they might not be able to adopt it. The outdated API might be used in a third-party library they cannot change.
Maintaining backward compatibility—even across major versions—has been a key factor in Spring Framework’s long-term popularity. I will undoubtedly return to this topic in future posts. In this one, I want to highlight a specific mistake from Spring 5 that was quietly fixed in Spring 6—without most users ever noticing.
The HttpMethod
Enumeration
Spring Framework 3.0 introduced the HttpMethod
enum, listing HTTP request methods (GET
, POST
, DELETE
, etc.).
It was designed for use within ClientHttpRequest
and ServerHttpRequest
, part of Spring’s internal HTTP abstraction layer.
Over time, its usage expanded.
First an abstraction over both client and server side was created with HttpRequest
.
Later, in version 5.0, it was reused for reactive support across both Netty and Servlet containers.
That latter expansion turned out to be a problem.
Originally intended for RESTful, client-side usage, HttpMethod
now had to represent all possible HTTP methods—including extensions like those used in WebDAV (LOCK
, COPY
etc.).
This mismatch came to light late in the release candidate phase of 5.0, when a bug was discovered: encountering an unknown HTTP method would throw an IllegalArgumentException
.
But it was too late for a clean fix.
The workaround was to introduce a getMethodValue()
method that returned the HTTP method as a String
.
This allowed users to access the raw value, even if it was not part of the enum.
HttpMethod method = request.getMethod();
if (method != null) {
// use enum
} else {
String methodValue = request.getMethodValue();
// fallback for unknown methods
}
This workaround worked—but it was ugly.
It forced users to handle null
values and duplicate logic.
Worse, it made the enum effectively redundant.
Despite this, the enum could not be removed.
Too much code relied on it.
The usual option in this kind of situation is to introduce a new, better type—say, HttpMethodValue
—and deprecate the old one.
But then you end up maintaining two parallel APIs for years, leading to confusion and frustration.
The Fix in Spring 6
Spring 6 brought a rare opportunity: the transition from Java EE to Jakarta EE required users to recompile their code anyway.
That gave us the chance to finally fix HttpMethod
.
In milestone 1 of Spring 6, HttpMethod
was changed from an enum
to a class.
Because a Java enum is just a special kind of class, we could retain most of its behavior:
- Constant fields for
GET
,POST
, etc. - A
valueOf
factory method - A
values()
method - Private constructor
- An implementation of
Comparable
andSerializable
With this change, getMethodValue()
could finally be deprecated.
Most users probably never noticed.
The API continued to work, and existing constants and methods were still available.
Only in edge cases—like using HttpMethod
in a switch
statement—did source changes become necessary.
The Broader Lesson
If you are writing code that others depend on, backward compatibility matters.
Breaking changes—especially for cosmetic or subjective reasons—are a great way to frustrate your users and push them away. Keeping your API stable is a sign of respect for their time and trust.
When a mistake is made, the cleanest fix is often to introduce an improved alternative, deprecate the original, and wait. Sometimes, with enough patience (or the right major version bump), you can remove the mistake entirely.
In the case of HttpMethod
, we were lucky.
We fixed it without breaking most users.
But chances like that are rare—and worth waiting for.