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

Java: Handle panics and errors in the Java FFI layer #355

Merged
merged 12 commits into from
Jun 18, 2024

Conversation

jonathanl-bq
Copy link

@jonathanl-bq jonathanl-bq commented Jun 9, 2024

This change restructures the FFI layer for the Java client to allow panics to be caught. It also allows errors to be caught in a more flexible and ergonomic manner. The API could theoretically be simplified further, but it is currently not feasible due to catch_unwind needing to take ownership of the JNIEnv due to this issue: jni-rs/jni-rs#432

java/client/build.gradle Show resolved Hide resolved
let value = unsafe { Box::from_raw(pointer as *mut Value) };
redis_value_to_java(env, *value, true)
}
let result = value_from_pointer(&mut env, pointer);

Choose a reason for hiding this comment

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

What is the benefit of defining a funcion and calling it right away?
Why can't we do this?

Suggested change
let result = value_from_pointer(&mut env, pointer);
let value = unsafe { Box::from_raw(pointer as *mut Value) };
let result = redis_value_to_java(env, *value, true);

Copy link
Author

Choose a reason for hiding this comment

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

In this case, there is no particular benefit. The reason why I define inner functions is because I didn't want to have to handle errors inline every single time I get a Result back (instead of using unwrap). To use ? syntax, you need a function that returns a Result though, so this is sort of a framework to follow. As for why I couldn't just roll this into another closure that is called from the closure passed to catch_unwind, it's because of this issue: jni-rs/jni-rs#432

Basically, the author of jni-rs didn't implement UnwindSafe for &mut JNIEnv, which means in order to use the JNIEnv, we need to own it inside of the closure instead of just borrowing it. If I were to pass the inner function as a closure, it would need to either borrow the JNIEnv (we can't do that), or always explicitly return the JNIEnv along with every payload, which is just unergonomic. As far as I can tell, there isn't a cleaner solution than this as long as that issue is still open. I could move the inner function definitions to the top level instead to avoid rightward drift, but that's just a style change.

Choose a reason for hiding this comment

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

Is it difficutl to

implement UnwindSafe for &mut JNIEnv

?
Maybe we you can contribute to jni-rs and later update our lib.rs once this fix released.

Copy link
Author

Choose a reason for hiding this comment

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

It's not possible to do this in our code because foreign traits cannot be implemented for foreign types. It would break trait coherence rules. It would need to be fixed upstream in jni-rs. I don't know how difficult it would be to implement this upstream. I'll need to try and see what goes wrong, but that's not a bad idea.

Choose a reason for hiding this comment

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

Yes I considered pushing a fix to jni-rs, but we shoudn't wait for it now.

Copy link

@Yury-Fridlyand Yury-Fridlyand left a comment

Choose a reason for hiding this comment

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

I propose to publish on upstream to get more detailed and professional review from amazon team

@jonathanl-bq jonathanl-bq merged commit 3f04b40 into java/integ_lotjonat_panics Jun 18, 2024
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants