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

Ensure Serializer runtime exceptions are rethrown as IOException #6969

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jack-berg
Copy link
Member

Resolves #6946, #6916.

@laurit interested in your thoughts on this as well, since its about the stateless marshalers.

Copy link

codecov bot commented Dec 18, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 90.11%. Comparing base (77b1f64) to head (4960e78).

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #6969      +/-   ##
============================================
+ Coverage     90.09%   90.11%   +0.02%     
  Complexity     6600     6600              
============================================
  Files           730      730              
  Lines         19843    19852       +9     
  Branches       1955     1955              
============================================
+ Hits          17877    17890      +13     
+ Misses         1371     1367       -4     
  Partials        595      595              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@laurit laurit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I don't see too many alternatives. I guess instead of UncheckedIOException could use a sneaky throw hack and throw the IOException without declaring it, but the current solution is probably easier to understand. Another alternative would be to reimplement the forEach and introduce a ThrowingConsumer, but that isn't desirable because we'd need to use iterator in our forEach variant while IdentityHashMap etc. implement it without extra allocations.

@jack-berg
Copy link
Member Author

I don't see too many alternatives.

One other option I thought of was to add a catch(RuntimeException) at the API entry point of serialization, just to make sure that no runtimeexception escapes. But I thought this was too blunt of a strategy - maybe there's some situation where its appropriate to let a runtime exception bubble up and go uncaught.

I guess instead of UncheckedIOException could use a sneaky throw hack and throw the IOException without declaring it

How does this work?

Another alternative would be to reimplement the forEach and introduce a ThrowingConsumer, but that isn't desirable because we'd need to use iterator in our forEach variant while IdentityHashMap etc.

I considered this as well and reached the same conclusion. In the past, benchmarks have shows extra memory allocation using an iterator vs. forEach. The other more pressing problem is that one of types we need to iterate through is Attributes, which doesn't expose an iterator. Moving away from Attributes.forEach would mean calling Attributes.asMap() which is obviously too expensive.

@laurit
Copy link
Contributor

laurit commented Dec 20, 2024

I guess instead of UncheckedIOException could use a sneaky throw hack and throw the IOException without declaring it

How does this work?

I believe the most common way is to use generics together with unchecked cast like in https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/cf0f530dc177951f457ffc2bc21c61382d4a10b7/instrumentation/reactor/reactor-3.1/library/src/main/java/io/opentelemetry/instrumentation/reactor/v3_1/ContextPropagationOperator.java#L250 which exploits generics and an unchecked cast to trick compiler to think that you are actually throwing a runtime exception. Here someone tracked down the part of the jls that makes this possible. I first saw this in https://www.google.com/search?q=java+puzzlers, for some reason I think that @breedx-splk has the book, idk why I remember it, could be wrong. Another way this could be done is using Class.newInstance, unlike the newer reflection apis it does not wrap the exception from constructor in InvocationTargetException (this should be the reason why it is deprecated). Of course, since the checked exceptions are a java not a jvm concept, it is possible to generate a class that accepts an arbitrary exception and just rethrows it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Encapsulated StreamResetException as IllegalStateException unhandled by the SDK
2 participants