Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HttpServerErrorException contains not-serializable field of type DefaultResponseErrorHandler #30224

Closed
walkeros opened this issue Mar 29, 2023 · 5 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Milestone

Comments

@walkeros
Copy link

walkeros commented Mar 29, 2023

In our app we use Spring Integration, which relies to some degree on java serialization. There in one spring integration endpoint which calls some rest api using standard RestTemplate. In case of 500 error from remote service the HttpServerErrorException is thrown. This exception is serialized later as it flows through Spring Integration channels.

Now this HttpServerErrorException subclasses RestClientResponseException which contains field bodyConvertFunction, which is by default set to DefaultResponseErrorHandler (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/DefaultResponseErrorHandler.html) which is not serializable.

As a result such dependency on this DefaultRespoinseErrorHandler, the instances of HttpServerErrorException are not serializable and causes this Spring Integration app to fail. Anyway it is not related to Spring Integration as the Exception should be serializable, meaning that all the fields should be serializable as well.

Interesting thing, that is seems that the linter was trying to highligt this issue, but it was surppressed in sources of : https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/client/RestClientResponseException.java


public class RestClientResponseException extends RestClientException {

	private static final long serialVersionUID = -8803556342728481792L;
(...)

	@Nullable
	@SuppressWarnings("serial")
	private Function<ResolvableType, ?> bodyConvertFunction;
}

Found in spring boot 3..0.2 (spring 6.0.4), but looking at source in github the issue seems to be there in newer versions

Interesting part of the exception message:

Caused by: java.io.NotSerializableException: org.springframework.web.client.DefaultResponseErrorHandler$$Lambda$4073/0x0000000801e6b7e0 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1197) ~[?:?] at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1582) ~[?:?] at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1539) ~[?:?] at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1448) ~[?:?] at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1191) ~[?:?] at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1582) ~[?:?] at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:447) ~[?:?] at java.lang.Throwable.writeObject(Throwable.java:1014) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?] at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1074) ~[?:?] at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1526) ~[?:?] at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1448) ~[?:?] at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1191) ~[?:?] at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1582) ~[?:?] at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:447) ~[?:?] at java.lang.Throwable.writeObject(Throwable.java:1014) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 29, 2023
@BrijeshPatra
Copy link

To resolve this issue, you can implement a custom ResponseErrorHandler that implements the Serializable interface or modify the DefaultResponseErrorHandler class to implement the Serializable interface. Another solution would be to avoid serializing the HttpServerErrorException object altogether and instead return a custom error response that can be serialized.

The issue you are facing with HttpServerErrorException containing a non-serializable field of type DefaultResponseErrorHandler is because the DefaultResponseErrorHandler class does not implement the Serializable interface. This means that it cannot be serialized by default and can cause issues when used in a context that requires serialization, such as when storing the HttpServerErrorException object in a distributed cache or passing it between different nodes in a distributed system.

@BrijeshPatra
Copy link

Here is the second way:

To fix this issue, you can make the DefaultResponseErrorHandler field transient, which means that it will not be included in the serialized form of the HttpServerErrorException object. You can then handle the error condition separately, perhaps by logging the error message or taking some other appropriate action.

Here's an example of how you can make the DefaultResponseErrorHandler field transient:
//CODE
public class HttpServerErrorException extends RuntimeException implements HttpStatusCodeException {

private transient DefaultResponseErrorHandler errorHandler;

// rest of the class implementation

}

@BrijeshPatra
Copy link

Subject: Seeking guidance on HttpServerErrorException issue

Hello @walkeros

My name is Brijesh Patra and I'm a new contributor to the spring framewprk project. I'm currently working on an issue related to the HttpServerErrorException, and I could use some guidance on how to proceed.

Specifically, I'm seeing an error message that says "HttpServerErrorException contains not-serializable field of type DefaultResponseErrorHandler." I've tried searching the codebase for occurrences of HttpServerErrorException, but I'm having trouble identifying the specific instance that is causing the issue.

I was wondering if you could provide some guidance on how to identify and resolve this issue. Should I be looking for the DefaultResponseErrorHandler class in the codebase, or is there another approach I should take? Any advice or pointers would be greatly appreciated.

Thank you so much for your time and help, and I look forward to contributing to the project!

Best regards
Brijesh

@rstoyanchev rstoyanchev added in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement labels Apr 11, 2023
@rstoyanchev rstoyanchev self-assigned this Apr 11, 2023
@rstoyanchev rstoyanchev removed the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 11, 2023
@rstoyanchev rstoyanchev added this to the 6.0.8 milestone Apr 11, 2023
@rstoyanchev
Copy link
Contributor

We can make the field transient. The getResponseBodyAs method is a convenience that becomes unavailable if the exception is serialized and deserialized.

@rstoyanchev
Copy link
Contributor

This is related to #28321, which applied the same changes to WebClientException.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants