Affects: Spring Framework 6.0.13
The change to ResponseEntity.getStatusCode()
returning the HttpStatusCode
interface instead of the HttpStatus
implementation breaks all callers that were expecting HttpStatus
returns.
Example error:
java.lang.NoSuchMethodError: 'org.springframework.http.HttpStatus org.springframework.http.ResponseEntity.getStatusCode()'
This break in backwards-compatibility has greatly impacted our migration to Spring Boot 3.x
Comment From: bclozel
Thanks for your feedback @Ed42 - this change was introduced in #28214. We realize this change is not transparent and this is why this was introduced in a major version. As you can see in the issue description, we took extra steps to minimize disruption in applications.
Unfortunately, we cannot change this arrangement at this stage. We would love to get this feedback during the milestone phases.
There is already a note in the upgrade wiki on HttpMethod
but not for this one. I guess this involved changing HttpStatus
assignments to HttpStatusCode
in your code? If you can explain more about the impact during the upgrade, maybe we can improve the wiki to help others. Still, I'm closing this issue now as there's nothing actionable in the project.
Thanks!
Comment From: Ed42
In Spring 5.x the HttpStatus
is an enum that does not implement any interfaces. In 6.x the same enum implements interface HttpStatusCode
, and it is this interface that is now returned by ResponseEntity.getStatusCode()
. This means there is no way to maintain a single piece of code that is compatible with both Spring major release versions. Company policy beyond my control precludes the use of milestone releases.
Such a breaking change is a poor choice without some mechanism for backwards compatibility, as this means we now have to maintain two versions of the same code while we are transitioning to Spring Boot 3.x, Spring 6.x. This project I'm working on has many Spring libraries, some of which are over 12 years old and have all worked perfectly for years. If they now start breaking unpredictably, even if the underlying reason has good rationale, this will complicate things enormously.
Comment From: bclozel
This means there is no way to maintain a single piece of code that is compatible with both Spring major release versions.
I think this is unrealistic expectations. Spring Framework 5 and 6 have very different baselines: JDK8 vs JDK17, Javax vs Jakarta, etc. For a Spring dependent library, I would assume a major version in sync with the baseline requirements of Spring itself.
Company policy beyond my control precludes the use of milestone releases.
I'm not suggesting usage of milestone versions in production, but rather testing milestone versions locally with existing applications to prepare future upgrades and send timely feedback to the team. Without this, you're effectively relying on the rest of the community to do that work for you. In this case, we had no complaints about this for 1.5 year and at this point it's too late to make any significant change about that.
Such a breaking change is a poor choice without some mechanism for backwards compatibility, as this means we now have to maintain two versions of the same code while we are transitioning to Spring Boot 3.x, Spring 6.x. This project I'm working on has many Spring libraries, some of which are over 12 years old and have all worked perfectly for years. If they now start breaking unpredictably, even if the underlying reason has good rationale, this will complicate things enormously.
I'm sorry this is making things more complicated for you, we're always trying to provide the best upgrade experience to the community. Still, I'm not sure it's fair to expect your library to be compatible with two major generations of Spring. There is no Spring project that does this in our entire portfolio for this very reason. If we cannot make any breaking change in major versions, there is simply no other way to make them and move the project forward.
Thanks for your feedback!
Comment From: CharlieReitzel
Still not clear on the compelling use case that justifies breaking so much code. How, specifically, does breaking ResponseEntity
"move the project forward"?
The way #28214 is written, it appears to be a theoretical concern. Are there any practical benefits to this change? Or is just another pedantic change foisted on 1000s of projects for academic reasons? Java developers already have a bad reputation. This just adds fuel to the fire ... :--)
Comment From: ae-govau
To add another data point, this change also broke us, not at compile time, but at runtime after deploying to an env. We depend on another library which depended on this, and now we need to go and find the maintainers of that other library, get them to re-write their code, publish a new version, then push a new version of our code.
I realise that transitive library dependency is impossible to solve fully, but it can be mitigated significantly by being prudent about the types of breaking changes that imposed on users of a library.
I'd argue in this case the same goal could have been met by adding a new method getExtendedHttpStatusCode()
or similar and deprecating the previous one, and without unnecessarily breaking all the dependent projects.
I realise it's too late this roll this one back, but I hope feedback like this is collected and used to inform future changes by the Spring teams.