Skip to content

Commit

Permalink
fix(binding/java): decode Java’s modified UTF-8 format (#3195)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-XD authored Sep 27, 2023
1 parent 0e55b92 commit 9315df4
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 20 deletions.
21 changes: 11 additions & 10 deletions bindings/java/src/blocking_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use jni::JNIEnv;

use opendal::BlockingOperator;

use crate::jstring_to_string;
use crate::Result;

/// # Safety
Expand Down Expand Up @@ -55,8 +56,8 @@ pub unsafe extern "system" fn Java_org_apache_opendal_BlockingOperator_read(
}

fn intern_read(env: &mut JNIEnv, op: &mut BlockingOperator, path: JString) -> Result<jbyteArray> {
let path = env.get_string(&path)?;
let content = op.read(path.to_str()?)?;
let path = jstring_to_string(env, &path)?;
let content = op.read(&path)?;
let result = env.byte_array_from_slice(content.as_slice())?;
Ok(result.into_raw())
}
Expand All @@ -83,9 +84,9 @@ fn intern_write(
path: JString,
content: JByteArray,
) -> Result<()> {
let path = env.get_string(&path)?;
let path = jstring_to_string(env, &path)?;
let content = env.convert_byte_array(content)?;
Ok(op.write(path.to_str()?, content)?)
Ok(op.write(&path, content)?)
}

/// # Safety
Expand All @@ -105,8 +106,8 @@ pub unsafe extern "system" fn Java_org_apache_opendal_BlockingOperator_stat(
}

fn intern_stat(env: &mut JNIEnv, op: &mut BlockingOperator, path: JString) -> Result<jlong> {
let path = env.get_string(&path)?;
let metadata = op.stat(path.to_str()?)?;
let path = jstring_to_string(env, &path)?;
let metadata = op.stat(&path)?;
Ok(Box::into_raw(Box::new(metadata)) as jlong)
}

Expand All @@ -126,8 +127,8 @@ pub unsafe extern "system" fn Java_org_apache_opendal_BlockingOperator_delete(
}

fn intern_delete(env: &mut JNIEnv, op: &mut BlockingOperator, path: JString) -> Result<()> {
let path = env.get_string(&path)?;
Ok(op.delete(path.to_str()?)?)
let path = jstring_to_string(env, &path)?;
Ok(op.delete(&path)?)
}

/// # Safety
Expand All @@ -146,6 +147,6 @@ pub unsafe extern "system" fn Java_org_apache_opendal_BlockingOperator_createDir
}

fn intern_create_dir(env: &mut JNIEnv, op: &mut BlockingOperator, path: JString) -> Result<()> {
let path = env.get_string(&path)?;
Ok(op.create_dir(path.to_str()?)?)
let path = jstring_to_string(env, &path)?;
Ok(op.create_dir(&path)?)
}
9 changes: 9 additions & 0 deletions bindings/java/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,12 @@ fn make_capability<'a>(env: &mut JNIEnv<'a>, cap: Capability) -> Result<JObject<
)?;
Ok(capability)
}

/// # Safety
///
/// The caller must guarantee that the Object passed in is an instance
/// of `java.lang.String`, passing in anything else will lead to undefined behavior.
fn jstring_to_string(env: &mut JNIEnv, s: &JString) -> Result<String> {
let res = unsafe { env.get_string_unchecked(s)? };
Ok(res.into())
}
21 changes: 11 additions & 10 deletions bindings/java/src/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use opendal::Scheme;
use crate::get_current_env;
use crate::get_global_runtime;
use crate::jmap_to_hashmap;
use crate::jstring_to_string;
use crate::make_operator_info;
use crate::make_presigned_request;
use crate::Result;
Expand All @@ -52,7 +53,7 @@ pub extern "system" fn Java_org_apache_opendal_Operator_constructor(
}

fn intern_constructor(env: &mut JNIEnv, scheme: JString, map: JObject) -> Result<jlong> {
let scheme = Scheme::from_str(env.get_string(&scheme)?.to_str()?)?;
let scheme = Scheme::from_str(jstring_to_string(env, &scheme)?.as_str())?;
let map = jmap_to_hashmap(env, &map)?;
let mut op = Operator::via_map(scheme, map)?;
if !op.info().full_capability().blocking {
Expand Down Expand Up @@ -100,7 +101,7 @@ fn intern_write(
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;
let content = env.convert_byte_array(content)?;

unsafe { get_global_runtime() }.spawn(async move {
Expand Down Expand Up @@ -141,7 +142,7 @@ fn intern_append(
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;
let content = env.convert_byte_array(content)?;

unsafe { get_global_runtime() }.spawn(async move {
Expand Down Expand Up @@ -176,7 +177,7 @@ fn intern_stat(env: &mut JNIEnv, op: *mut Operator, path: JString) -> Result<jlo
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;

unsafe { get_global_runtime() }.spawn(async move {
let result = do_stat(op, path).await;
Expand Down Expand Up @@ -211,7 +212,7 @@ fn intern_read(env: &mut JNIEnv, op: *mut Operator, path: JString) -> Result<jlo
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;

unsafe { get_global_runtime() }.spawn(async move {
let result = do_read(op, path).await;
Expand Down Expand Up @@ -249,7 +250,7 @@ fn intern_delete(env: &mut JNIEnv, op: *mut Operator, path: JString) -> Result<j
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;

unsafe { get_global_runtime() }.spawn(async move {
let result = do_delete(op, path).await;
Expand Down Expand Up @@ -316,7 +317,7 @@ fn intern_create_dir(env: &mut JNIEnv, op: *mut Operator, path: JString) -> Resu
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;

unsafe { get_global_runtime() }.spawn(async move {
let result = do_create_dir(op, path).await;
Expand Down Expand Up @@ -356,7 +357,7 @@ fn intern_presign_read(
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;
let expire = Duration::from_nanos(expire as u64);

unsafe { get_global_runtime() }.spawn(async move {
Expand Down Expand Up @@ -403,7 +404,7 @@ fn intern_presign_write(
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;
let expire = Duration::from_nanos(expire as u64);

unsafe { get_global_runtime() }.spawn(async move {
Expand Down Expand Up @@ -450,7 +451,7 @@ fn intern_presign_stat(
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = env.get_string(&path)?.to_str()?.to_string();
let path = jstring_to_string(env, &path)?;
let expire = Duration::from_nanos(expire as u64);

unsafe { get_global_runtime() }.spawn(async move {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,21 @@ public void testStatFile() {
}
operator.delete(path).join();
}

/**
* Write file with non ascii name should succeed.
*/
@Test
public void testWriteFileWithNonAsciiName() {
final String path = "❌😱中文.test";
final byte[] content = generateBytes();
operator.write(path, content).join();
try (final Metadata meta = operator.stat(path).join()) {
assertThat(meta.isFile()).isTrue();
assertThat(meta.getContentLength()).isEqualTo(content.length);
}
operator.delete(path).join();
}
}

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
Expand Down

0 comments on commit 9315df4

Please sign in to comment.