From 9260350fd470aeb01a8dc9363702def69ff8f5b0 Mon Sep 17 00:00:00 2001 From: Inseok Lee Date: Wed, 12 Aug 2026 08:19:02 +0900 Subject: [PATCH 1/2] Fix Cloneable and Serializable class metadata --- java_runtime/src/classes/java/io/file.rs | 2 +- java_runtime/src/classes/java/lang/class.rs | 2 +- .../src/classes/java/lang/throwable.rs | 2 +- java_runtime/src/classes/java/net/url.rs | 2 +- .../src/classes/java/util/array_list.rs | 2 +- .../src/classes/java/util/calendar.rs | 2 +- .../src/classes/java/util/hash_map.rs | 2 +- .../src/classes/java/util/hash_set.rs | 2 +- .../src/classes/java/util/hashtable.rs | 2 +- .../src/classes/java/util/jar/attributes.rs | 2 +- .../src/classes/java/util/jar/manifest.rs | 2 +- .../src/classes/java/util/logging/level.rs | 2 +- .../classes/java/util/logging/log_record.rs | 2 +- java_runtime/src/classes/java/util/vector.rs | 2 +- .../src/classes/java/util/zip/zip_entry.rs | 2 +- java_runtime/tests/classes/java/mod.rs | 1 + .../classes/java/test_marker_interfaces.rs | 105 ++++++++++++++++++ jvm/src/jvm.rs | 9 +- 18 files changed, 129 insertions(+), 16 deletions(-) create mode 100644 java_runtime/tests/classes/java/test_marker_interfaces.rs diff --git a/java_runtime/src/classes/java/io/file.rs b/java_runtime/src/classes/java/io/file.rs index 91a26e51..905fd83e 100644 --- a/java_runtime/src/classes/java/io/file.rs +++ b/java_runtime/src/classes/java/io/file.rs @@ -14,7 +14,7 @@ impl File { RuntimeClassProto { name: "java/io/File", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::clinit, MethodAccessFlags::STATIC), JavaMethodProto::new("", "(Ljava/lang/String;)V", Self::init, Default::default()), diff --git a/java_runtime/src/classes/java/lang/class.rs b/java_runtime/src/classes/java/lang/class.rs index eec466a3..2891c88d 100644 --- a/java_runtime/src/classes/java/lang/class.rs +++ b/java_runtime/src/classes/java/lang/class.rs @@ -23,7 +23,7 @@ impl Class { RuntimeClassProto { name: "java/lang/Class", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new("getName", "()Ljava/lang/String;", Self::get_name, Default::default()), diff --git a/java_runtime/src/classes/java/lang/throwable.rs b/java_runtime/src/classes/java/lang/throwable.rs index 12ef890c..48e9cf79 100644 --- a/java_runtime/src/classes/java/lang/throwable.rs +++ b/java_runtime/src/classes/java/lang/throwable.rs @@ -20,7 +20,7 @@ impl Throwable { RuntimeClassProto { name: "java/lang/Throwable", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new("", "(Ljava/lang/String;)V", Self::init_with_message, Default::default()), diff --git a/java_runtime/src/classes/java/net/url.rs b/java_runtime/src/classes/java/net/url.rs index 20f65e70..a21f1822 100644 --- a/java_runtime/src/classes/java/net/url.rs +++ b/java_runtime/src/classes/java/net/url.rs @@ -20,7 +20,7 @@ impl URL { RuntimeClassProto { name: "java/net/URL", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "(Ljava/lang/String;)V", Self::init_with_spec, Default::default()), JavaMethodProto::new( diff --git a/java_runtime/src/classes/java/util/array_list.rs b/java_runtime/src/classes/java/util/array_list.rs index 21c9264a..695d8616 100644 --- a/java_runtime/src/classes/java/util/array_list.rs +++ b/java_runtime/src/classes/java/util/array_list.rs @@ -14,7 +14,7 @@ impl ArrayList { RuntimeClassProto { name: "java/util/ArrayList", parent_class: Some("java/util/AbstractList"), - interfaces: vec![], + interfaces: vec!["java/lang/Cloneable", "java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new("", "(I)V", Self::init_with_capacity, Default::default()), diff --git a/java_runtime/src/classes/java/util/calendar.rs b/java_runtime/src/classes/java/util/calendar.rs index fed9991f..0e9338f1 100644 --- a/java_runtime/src/classes/java/util/calendar.rs +++ b/java_runtime/src/classes/java/util/calendar.rs @@ -20,7 +20,7 @@ impl Calendar { RuntimeClassProto { name: "java/util/Calendar", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/io/Serializable", "java/lang/Cloneable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new("getInstance", "()Ljava/util/Calendar;", Self::get_instance, MethodAccessFlags::STATIC), diff --git a/java_runtime/src/classes/java/util/hash_map.rs b/java_runtime/src/classes/java/util/hash_map.rs index e43d0271..177e9626 100644 --- a/java_runtime/src/classes/java/util/hash_map.rs +++ b/java_runtime/src/classes/java/util/hash_map.rs @@ -19,7 +19,7 @@ impl HashMap { RuntimeClassProto { name: "java/util/HashMap", parent_class: Some("java/util/AbstractMap"), - interfaces: vec![], + interfaces: vec!["java/lang/Cloneable", "java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, MethodAccessFlags::PUBLIC), JavaMethodProto::new("", "(I)V", Self::init_with_capacity, MethodAccessFlags::PUBLIC), diff --git a/java_runtime/src/classes/java/util/hash_set.rs b/java_runtime/src/classes/java/util/hash_set.rs index ffa5fc20..508afabd 100644 --- a/java_runtime/src/classes/java/util/hash_set.rs +++ b/java_runtime/src/classes/java/util/hash_set.rs @@ -18,7 +18,7 @@ impl HashSet { RuntimeClassProto { name: "java/util/HashSet", parent_class: Some("java/util/AbstractSet"), - interfaces: vec![], + interfaces: vec!["java/lang/Cloneable", "java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new("", "(I)V", Self::init_with_capacity, Default::default()), diff --git a/java_runtime/src/classes/java/util/hashtable.rs b/java_runtime/src/classes/java/util/hashtable.rs index d0ed3bca..07ebe21a 100644 --- a/java_runtime/src/classes/java/util/hashtable.rs +++ b/java_runtime/src/classes/java/util/hashtable.rs @@ -22,7 +22,7 @@ impl Hashtable { RuntimeClassProto { name: "java/util/Hashtable", parent_class: Some("java/util/Dictionary"), - interfaces: vec!["java/util/Map"], + interfaces: vec!["java/util/Map", "java/lang/Cloneable", "java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new("", "(I)V", Self::init_with_capacity, Default::default()), diff --git a/java_runtime/src/classes/java/util/jar/attributes.rs b/java_runtime/src/classes/java/util/jar/attributes.rs index aa506bd0..9f20ac97 100644 --- a/java_runtime/src/classes/java/util/jar/attributes.rs +++ b/java_runtime/src/classes/java/util/jar/attributes.rs @@ -13,7 +13,7 @@ impl Attributes { RuntimeClassProto { name: "java/util/jar/Attributes", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/lang/Cloneable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new( diff --git a/java_runtime/src/classes/java/util/jar/manifest.rs b/java_runtime/src/classes/java/util/jar/manifest.rs index 7273f753..ce6a0908 100644 --- a/java_runtime/src/classes/java/util/jar/manifest.rs +++ b/java_runtime/src/classes/java/util/jar/manifest.rs @@ -16,7 +16,7 @@ impl Manifest { RuntimeClassProto { name: "java/util/jar/Manifest", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/lang/Cloneable"], methods: vec![ JavaMethodProto::new("", "(Ljava/io/InputStream;)V", Self::init, Default::default()), JavaMethodProto::new("read", "(Ljava/io/InputStream;)V", Self::read, Default::default()), diff --git a/java_runtime/src/classes/java/util/logging/level.rs b/java_runtime/src/classes/java/util/logging/level.rs index 5b2b3352..7379652f 100644 --- a/java_runtime/src/classes/java/util/logging/level.rs +++ b/java_runtime/src/classes/java/util/logging/level.rs @@ -17,7 +17,7 @@ impl Level { RuntimeClassProto { name: "java/util/logging/Level", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::clinit, MethodAccessFlags::STATIC), JavaMethodProto::new("", "(Ljava/lang/String;I)V", Self::init, MethodAccessFlags::PROTECTED), diff --git a/java_runtime/src/classes/java/util/logging/log_record.rs b/java_runtime/src/classes/java/util/logging/log_record.rs index 24aeebe7..095cafac 100644 --- a/java_runtime/src/classes/java/util/logging/log_record.rs +++ b/java_runtime/src/classes/java/util/logging/log_record.rs @@ -19,7 +19,7 @@ impl LogRecord { RuntimeClassProto { name: "java/util/logging/LogRecord", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/io/Serializable"], methods: vec![ JavaMethodProto::new( "", diff --git a/java_runtime/src/classes/java/util/vector.rs b/java_runtime/src/classes/java/util/vector.rs index 9cacb6ab..8cfd94e5 100644 --- a/java_runtime/src/classes/java/util/vector.rs +++ b/java_runtime/src/classes/java/util/vector.rs @@ -22,7 +22,7 @@ impl Vector { RuntimeClassProto { name: "java/util/Vector", parent_class: Some("java/util/AbstractList"), - interfaces: vec!["java/util/List"], + interfaces: vec!["java/util/List", "java/lang/Cloneable", "java/io/Serializable"], methods: vec![ JavaMethodProto::new("", "()V", Self::init, Default::default()), JavaMethodProto::new("", "(I)V", Self::init_with_capacity, Default::default()), diff --git a/java_runtime/src/classes/java/util/zip/zip_entry.rs b/java_runtime/src/classes/java/util/zip/zip_entry.rs index 6db0ef83..46a40ea9 100644 --- a/java_runtime/src/classes/java/util/zip/zip_entry.rs +++ b/java_runtime/src/classes/java/util/zip/zip_entry.rs @@ -13,7 +13,7 @@ impl ZipEntry { RuntimeClassProto { name: "java/util/zip/ZipEntry", parent_class: Some("java/lang/Object"), - interfaces: vec![], + interfaces: vec!["java/lang/Cloneable"], methods: vec![ JavaMethodProto::new("", "(Ljava/lang/String;)V", Self::init, Default::default()), JavaMethodProto::new("", "(Ljava/util/zip/ZipEntry;)V", Self::init_with_zip_entry, Default::default()), diff --git a/java_runtime/tests/classes/java/mod.rs b/java_runtime/tests/classes/java/mod.rs index 998c6719..70926da0 100644 --- a/java_runtime/tests/classes/java/mod.rs +++ b/java_runtime/tests/classes/java/mod.rs @@ -1,5 +1,6 @@ mod io; mod lang; mod net; +mod test_marker_interfaces; mod text; mod util; diff --git a/java_runtime/tests/classes/java/test_marker_interfaces.rs b/java_runtime/tests/classes/java/test_marker_interfaces.rs new file mode 100644 index 00000000..a006569b --- /dev/null +++ b/java_runtime/tests/classes/java/test_marker_interfaces.rs @@ -0,0 +1,105 @@ +use java_runtime::classes::java::lang::Class; +use jvm::{Array, ClassInstanceRef, Result, runtime::JavaLangClass}; +use test_utils::test_jvm; + +#[tokio::test] +async fn marker_interfaces_match_public_class_declarations() -> Result<()> { + let jvm = test_jvm().await?; + + let direct_markers: [(&str, &[&str]); 15] = [ + ("java/lang/Throwable", &["java/io/Serializable"]), + ("java/lang/Class", &["java/io/Serializable"]), + ("java/io/File", &["java/io/Serializable"]), + ("java/net/URL", &["java/io/Serializable"]), + ("java/util/Calendar", &["java/io/Serializable", "java/lang/Cloneable"]), + ("java/util/ArrayList", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/HashMap", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/HashSet", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/Hashtable", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/Vector", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/jar/Attributes", &["java/lang/Cloneable"]), + ("java/util/jar/Manifest", &["java/lang/Cloneable"]), + ("java/util/logging/Level", &["java/io/Serializable"]), + ("java/util/logging/LogRecord", &["java/io/Serializable"]), + ("java/util/zip/ZipEntry", &["java/lang/Cloneable"]), + ]; + + for (class_name, expected_markers) in direct_markers { + let class = jvm.resolve_class(class_name).await?.java_class(); + let interfaces: ClassInstanceRef> = jvm.invoke_virtual(&class, "getInterfaces", "()[Ljava/lang/Class;", ()).await?; + let interfaces: Vec> = jvm.load_array(&interfaces, 0, jvm.array_length(&interfaces).await?).await?; + let mut actual_markers = Vec::new(); + for interface in interfaces { + let interface_name = JavaLangClass::name(&jvm, &interface).await?; + if interface_name == "java/lang/Cloneable" || interface_name == "java/io/Serializable" { + actual_markers.push(interface_name); + } + } + assert_eq!( + actual_markers.iter().map(String::as_str).collect::>(), + expected_markers, + "incorrect direct marker interfaces for {class_name}" + ); + + for marker_name in expected_markers { + let marker = jvm.resolve_class(marker_name).await?.java_class(); + assert!( + jvm.invoke_virtual::<_, bool>(&marker, "isAssignableFrom", "(Ljava/lang/Class;)Z", (class.clone(),)) + .await?, + "{class_name} must implement {marker_name}" + ); + } + } + + let inherited_markers: [(&str, &[&str]); 6] = [ + ("java/lang/RuntimeException", &["java/io/Serializable"]), + ("java/util/GregorianCalendar", &["java/io/Serializable", "java/lang/Cloneable"]), + ("java/util/Properties", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/Stack", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/LinkedHashMap", &["java/lang/Cloneable", "java/io/Serializable"]), + ("java/util/jar/JarEntry", &["java/lang/Cloneable"]), + ]; + + for (class_name, expected_markers) in inherited_markers { + let class = jvm.resolve_class(class_name).await?.java_class(); + let interfaces: ClassInstanceRef> = jvm.invoke_virtual(&class, "getInterfaces", "()[Ljava/lang/Class;", ()).await?; + let interfaces: Vec> = jvm.load_array(&interfaces, 0, jvm.array_length(&interfaces).await?).await?; + for interface in interfaces { + let interface_name = JavaLangClass::name(&jvm, &interface).await?; + assert!( + interface_name != "java/lang/Cloneable" && interface_name != "java/io/Serializable", + "{class_name} must inherit {interface_name}, not declare it directly" + ); + } + + for marker_name in expected_markers { + let marker = jvm.resolve_class(marker_name).await?.java_class(); + assert!( + jvm.invoke_virtual::<_, bool>(&marker, "isAssignableFrom", "(Ljava/lang/Class;)Z", (class.clone(),)) + .await?, + "{class_name} must inherit {marker_name}" + ); + } + } + + for class_name in ["java/text/FieldPosition", "java/text/ParsePosition"] { + let class = jvm.resolve_class(class_name).await?.java_class(); + let interfaces: ClassInstanceRef> = jvm.invoke_virtual(&class, "getInterfaces", "()[Ljava/lang/Class;", ()).await?; + let interfaces: Vec> = jvm.load_array(&interfaces, 0, jvm.array_length(&interfaces).await?).await?; + for interface in interfaces { + let interface_name = JavaLangClass::name(&jvm, &interface).await?; + assert!(interface_name != "java/lang/Cloneable" && interface_name != "java/io/Serializable"); + } + + for marker_name in ["java/lang/Cloneable", "java/io/Serializable"] { + let marker = jvm.resolve_class(marker_name).await?.java_class(); + assert!( + !jvm.invoke_virtual::<_, bool>(&marker, "isAssignableFrom", "(Ljava/lang/Class;)Z", (class.clone(),)) + .await?, + "{class_name} must not implement {marker_name}" + ); + } + } + + Ok(()) +} diff --git a/jvm/src/jvm.rs b/jvm/src/jvm.rs index 105bb4ca..f74603a8 100644 --- a/jvm/src/jvm.rs +++ b/jvm/src/jvm.rs @@ -79,7 +79,14 @@ impl Jvm { }; // load bootstrap classes - let bootstrap_classes = ["java/lang/Object", "java/lang/Runnable", "java/lang/Thread", "[B", "java/lang/Class"]; + let bootstrap_classes = [ + "java/lang/Object", + "java/lang/Runnable", + "java/lang/Thread", + "[B", + "java/io/Serializable", + "java/lang/Class", + ]; for class_name in bootstrap_classes.iter() { let class_definition = jvm.inner.bootstrap_class_loader.load_class(&jvm, class_name).await?.unwrap(); let class = Class::new(class_definition, None); From 27822c85b4c8c47de2461475ddbd8cd5266ff6c7 Mon Sep 17 00:00:00 2001 From: Inseok Lee Date: Wed, 12 Aug 2026 19:11:04 +0900 Subject: [PATCH 2/2] Remove cross-package marker metadata test --- java_runtime/tests/classes/java/mod.rs | 1 - .../classes/java/test_marker_interfaces.rs | 105 ------------------ 2 files changed, 106 deletions(-) delete mode 100644 java_runtime/tests/classes/java/test_marker_interfaces.rs diff --git a/java_runtime/tests/classes/java/mod.rs b/java_runtime/tests/classes/java/mod.rs index 70926da0..998c6719 100644 --- a/java_runtime/tests/classes/java/mod.rs +++ b/java_runtime/tests/classes/java/mod.rs @@ -1,6 +1,5 @@ mod io; mod lang; mod net; -mod test_marker_interfaces; mod text; mod util; diff --git a/java_runtime/tests/classes/java/test_marker_interfaces.rs b/java_runtime/tests/classes/java/test_marker_interfaces.rs deleted file mode 100644 index a006569b..00000000 --- a/java_runtime/tests/classes/java/test_marker_interfaces.rs +++ /dev/null @@ -1,105 +0,0 @@ -use java_runtime::classes::java::lang::Class; -use jvm::{Array, ClassInstanceRef, Result, runtime::JavaLangClass}; -use test_utils::test_jvm; - -#[tokio::test] -async fn marker_interfaces_match_public_class_declarations() -> Result<()> { - let jvm = test_jvm().await?; - - let direct_markers: [(&str, &[&str]); 15] = [ - ("java/lang/Throwable", &["java/io/Serializable"]), - ("java/lang/Class", &["java/io/Serializable"]), - ("java/io/File", &["java/io/Serializable"]), - ("java/net/URL", &["java/io/Serializable"]), - ("java/util/Calendar", &["java/io/Serializable", "java/lang/Cloneable"]), - ("java/util/ArrayList", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/HashMap", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/HashSet", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/Hashtable", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/Vector", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/jar/Attributes", &["java/lang/Cloneable"]), - ("java/util/jar/Manifest", &["java/lang/Cloneable"]), - ("java/util/logging/Level", &["java/io/Serializable"]), - ("java/util/logging/LogRecord", &["java/io/Serializable"]), - ("java/util/zip/ZipEntry", &["java/lang/Cloneable"]), - ]; - - for (class_name, expected_markers) in direct_markers { - let class = jvm.resolve_class(class_name).await?.java_class(); - let interfaces: ClassInstanceRef> = jvm.invoke_virtual(&class, "getInterfaces", "()[Ljava/lang/Class;", ()).await?; - let interfaces: Vec> = jvm.load_array(&interfaces, 0, jvm.array_length(&interfaces).await?).await?; - let mut actual_markers = Vec::new(); - for interface in interfaces { - let interface_name = JavaLangClass::name(&jvm, &interface).await?; - if interface_name == "java/lang/Cloneable" || interface_name == "java/io/Serializable" { - actual_markers.push(interface_name); - } - } - assert_eq!( - actual_markers.iter().map(String::as_str).collect::>(), - expected_markers, - "incorrect direct marker interfaces for {class_name}" - ); - - for marker_name in expected_markers { - let marker = jvm.resolve_class(marker_name).await?.java_class(); - assert!( - jvm.invoke_virtual::<_, bool>(&marker, "isAssignableFrom", "(Ljava/lang/Class;)Z", (class.clone(),)) - .await?, - "{class_name} must implement {marker_name}" - ); - } - } - - let inherited_markers: [(&str, &[&str]); 6] = [ - ("java/lang/RuntimeException", &["java/io/Serializable"]), - ("java/util/GregorianCalendar", &["java/io/Serializable", "java/lang/Cloneable"]), - ("java/util/Properties", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/Stack", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/LinkedHashMap", &["java/lang/Cloneable", "java/io/Serializable"]), - ("java/util/jar/JarEntry", &["java/lang/Cloneable"]), - ]; - - for (class_name, expected_markers) in inherited_markers { - let class = jvm.resolve_class(class_name).await?.java_class(); - let interfaces: ClassInstanceRef> = jvm.invoke_virtual(&class, "getInterfaces", "()[Ljava/lang/Class;", ()).await?; - let interfaces: Vec> = jvm.load_array(&interfaces, 0, jvm.array_length(&interfaces).await?).await?; - for interface in interfaces { - let interface_name = JavaLangClass::name(&jvm, &interface).await?; - assert!( - interface_name != "java/lang/Cloneable" && interface_name != "java/io/Serializable", - "{class_name} must inherit {interface_name}, not declare it directly" - ); - } - - for marker_name in expected_markers { - let marker = jvm.resolve_class(marker_name).await?.java_class(); - assert!( - jvm.invoke_virtual::<_, bool>(&marker, "isAssignableFrom", "(Ljava/lang/Class;)Z", (class.clone(),)) - .await?, - "{class_name} must inherit {marker_name}" - ); - } - } - - for class_name in ["java/text/FieldPosition", "java/text/ParsePosition"] { - let class = jvm.resolve_class(class_name).await?.java_class(); - let interfaces: ClassInstanceRef> = jvm.invoke_virtual(&class, "getInterfaces", "()[Ljava/lang/Class;", ()).await?; - let interfaces: Vec> = jvm.load_array(&interfaces, 0, jvm.array_length(&interfaces).await?).await?; - for interface in interfaces { - let interface_name = JavaLangClass::name(&jvm, &interface).await?; - assert!(interface_name != "java/lang/Cloneable" && interface_name != "java/io/Serializable"); - } - - for marker_name in ["java/lang/Cloneable", "java/io/Serializable"] { - let marker = jvm.resolve_class(marker_name).await?.java_class(); - assert!( - !jvm.invoke_virtual::<_, bool>(&marker, "isAssignableFrom", "(Ljava/lang/Class;)Z", (class.clone(),)) - .await?, - "{class_name} must not implement {marker_name}" - ); - } - } - - Ok(()) -}