Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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> {
Comment thread
G-XD marked this conversation as resolved.
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