Skip to content

Commit bcd6995

Browse files
committed
Add clone exception
1 parent c33dc81 commit bcd6995

File tree

7 files changed

+97
-7
lines changed

7 files changed

+97
-7
lines changed

java_runtime/src/classes/java/lang.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod array_index_out_of_bounds_exception;
22
mod class;
33
mod class_loader;
4+
mod cloneable;
45
mod error;
56
mod exception;
67
mod illegal_argument_exception;
@@ -15,6 +16,7 @@ mod no_class_def_found_error;
1516
mod no_such_field_error;
1617
mod no_such_method_error;
1718
mod null_pointer_exception;
19+
mod clone_not_supported_exception;
1820
mod object;
1921
mod runnable;
2022
mod runtime;
@@ -28,12 +30,12 @@ mod throwable;
2830
mod unsupported_operation_exception;
2931

3032
pub use self::{
31-
array_index_out_of_bounds_exception::ArrayIndexOutOfBoundsException, class::Class, class_loader::ClassLoader, error::Error, exception::Exception,
32-
illegal_argument_exception::IllegalArgumentException, incompatible_class_change_error::IncompatibleClassChangeError,
33+
array_index_out_of_bounds_exception::ArrayIndexOutOfBoundsException, class::Class, class_loader::ClassLoader, cloneable::Cloneable, error::Error,
34+
exception::Exception, illegal_argument_exception::IllegalArgumentException, incompatible_class_change_error::IncompatibleClassChangeError,
3335
index_out_of_bounds_exception::IndexOutOfBoundsException, instantiation_error::InstantiationError, integer::Integer,
3436
interrupted_exception::InterruptedException, linkage_error::LinkageError, math::Math, no_class_def_found_error::NoClassDefFoundError,
3537
no_such_field_error::NoSuchFieldError, no_such_method_error::NoSuchMethodError, null_pointer_exception::NullPointerException, object::Object,
3638
runnable::Runnable, runtime::Runtime, runtime_exception::RuntimeException, security_exception::SecurityException, string::String,
3739
string_buffer::StringBuffer, system::System, thread::Thread, throwable::Throwable,
38-
unsupported_operation_exception::UnsupportedOperationException,
40+
unsupported_operation_exception::UnsupportedOperationException, clone_not_supported_exception::CloneNotSupportedException,
3941
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use alloc::vec;
2+
3+
use java_class_proto::JavaMethodProto;
4+
use jvm::{ClassInstanceRef, Jvm, Result};
5+
6+
use crate::{RuntimeClassProto, RuntimeContext, classes::java::lang::String};
7+
8+
// class java.lang.CloneNotSupportedException
9+
pub struct CloneNotSupportedException;
10+
11+
impl CloneNotSupportedException {
12+
pub fn as_proto() -> RuntimeClassProto {
13+
RuntimeClassProto {
14+
name: "java/lang/CloneNotSupportedException",
15+
parent_class: Some("java/lang/Exception"),
16+
interfaces: vec![],
17+
methods: vec![
18+
JavaMethodProto::new("<init>", "()V", Self::init, Default::default()),
19+
JavaMethodProto::new("<init>", "(Ljava/lang/String;)V", Self::init_with_message, Default::default()),
20+
],
21+
fields: vec![],
22+
access_flags: Default::default(),
23+
}
24+
}
25+
26+
async fn init(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
27+
tracing::debug!("java.lang.CloneNotSupportedException::<init>({:?})", &this);
28+
29+
let _: () = jvm.invoke_special(&this, "java/lang/Exception", "<init>", "()V", ()).await?;
30+
31+
Ok(())
32+
}
33+
34+
async fn init_with_message(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, message: ClassInstanceRef<String>) -> Result<()> {
35+
tracing::debug!("java.lang.CloneNotSupportedException::<init>({:?}, {:?})", &this, &message);
36+
37+
let _: () = jvm
38+
.invoke_special(&this, "java/lang/Exception", "<init>", "(Ljava/lang/String;)V", (message,))
39+
.await?;
40+
41+
Ok(())
42+
}
43+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use alloc::vec;
2+
3+
use java_constants::ClassAccessFlags;
4+
5+
use crate::RuntimeClassProto;
6+
7+
// interface java.lang.Cloneable
8+
pub struct Cloneable;
9+
10+
impl Cloneable {
11+
pub fn as_proto() -> RuntimeClassProto {
12+
RuntimeClassProto {
13+
name: "java/lang/Cloneable",
14+
parent_class: None,
15+
interfaces: vec![],
16+
methods: vec![],
17+
fields: vec![],
18+
access_flags: ClassAccessFlags::INTERFACE,
19+
}
20+
}
21+
}

java_runtime/src/classes/java/lang/object.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl Object {
2525
JavaMethodProto::new("getClass", "()Ljava/lang/Class;", Self::get_class, Default::default()),
2626
JavaMethodProto::new("hashCode", "()I", Self::hash_code, Default::default()),
2727
JavaMethodProto::new("equals", "(Ljava/lang/Object;)Z", Self::equals, Default::default()),
28-
JavaMethodProto::new("clone", "()Ljava/lang/Object;", Self::java_clone, MethodAccessFlags::NATIVE),
28+
JavaMethodProto::new("clone", "()Ljava/lang/Object;", Self::clone, MethodAccessFlags::NATIVE),
2929
JavaMethodProto::new("toString", "()Ljava/lang/String;", Self::to_string, Default::default()),
3030
JavaMethodProto::new("notify", "()V", Self::notify, Default::default()),
3131
JavaMethodProto::new("notifyAll", "()V", Self::notify_all, Default::default()),
@@ -80,9 +80,13 @@ impl Object {
8080
rust_this.equals(&*rust_other)
8181
}
8282

83-
async fn java_clone(_: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Self>> {
83+
async fn clone(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Self>> {
8484
tracing::warn!("stub java.lang.Object::clone({:?})", &this);
8585

86+
if !jvm.is_instance(&**this, "java/lang/Cloneable") {
87+
return Err(jvm.exception("java/lang/CloneNotSupportedException", "Cannot clone this object").await);
88+
}
89+
8690
Ok(None.into())
8791
}
8892

java_runtime/src/classes/java/lang/runnable.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use crate::RuntimeClassProto;
99
pub struct Runnable;
1010

1111
impl Runnable {
12-
// TODO Create JavaInterfaceProto
1312
pub fn as_proto() -> RuntimeClassProto {
1413
RuntimeClassProto {
1514
name: "java/lang/Runnable",

java_runtime/src/loader.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ pub fn get_runtime_class_proto(name: &str) -> Option<RuntimeClassProto> {
3434
crate::classes::java::lang::ArrayIndexOutOfBoundsException::as_proto(),
3535
crate::classes::java::lang::Class::as_proto(),
3636
crate::classes::java::lang::ClassLoader::as_proto(),
37+
crate::classes::java::lang::Cloneable::as_proto(),
38+
crate::classes::java::lang::CloneNotSupportedException::as_proto(),
3739
crate::classes::java::lang::Error::as_proto(),
3840
crate::classes::java::lang::Exception::as_proto(),
3941
crate::classes::java::lang::IllegalArgumentException::as_proto(),

java_runtime/tests/classes/java/lang/test_object.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use core::{
2+
panic,
23
sync::atomic::{AtomicBool, Ordering},
34
time::Duration,
45
};
56

67
use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc};
78

89
use java_runtime::{Runtime, SpawnCallback, classes::java::lang::Object};
9-
use jvm::{ClassInstanceRef, Jvm, Result};
10+
use jvm::{ClassInstanceRef, JavaError, Jvm, Result};
1011

1112
use test_utils::{TestRuntime, create_test_jvm};
1213

@@ -104,3 +105,21 @@ async fn test_wait_timeout() -> Result<()> {
104105

105106
Ok(())
106107
}
108+
109+
#[tokio::test]
110+
async fn test_clone_not_cloneable() -> Result<()> {
111+
let runtime = TestRuntime::new(BTreeMap::new());
112+
let jvm = create_test_jvm(runtime.clone()).await?;
113+
114+
let object = jvm.new_class("java/lang/Object", "()V", ()).await?;
115+
116+
let result: Result<ClassInstanceRef<Object>> = jvm.invoke_virtual(&object, "clone", "()Ljava/lang/Object;", ()).await;
117+
let Err(JavaError::JavaException(java_exception)) = result else {
118+
panic!("Expected JavaException, got {:?}", result);
119+
};
120+
121+
let class_name = java_exception.class_definition().name();
122+
assert_eq!(class_name, "java/lang/CloneNotSupportedException");
123+
124+
Ok(())
125+
}

0 commit comments

Comments
 (0)