-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathclass.rs
More file actions
110 lines (90 loc) · 4.31 KB
/
class.rs
File metadata and controls
110 lines (90 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use alloc::vec;
use java_class_proto::{JavaFieldProto, JavaMethodProto};
use java_constants::MethodAccessFlags;
use jvm::{
ClassInstanceRef, Jvm, Result,
runtime::{JavaLangClass, JavaLangClassLoader, JavaLangString},
};
use crate::{
RuntimeClassProto, RuntimeContext,
classes::java::{
io::InputStream,
lang::{ClassLoader, String},
},
};
// class java.lang.Class
pub struct Class;
impl Class {
pub fn as_proto() -> RuntimeClassProto {
RuntimeClassProto {
name: "java/lang/Class",
parent_class: Some("java/lang/Object"),
interfaces: vec![],
methods: vec![
JavaMethodProto::new("<init>", "()V", Self::init, Default::default()),
JavaMethodProto::new("getName", "()Ljava/lang/String;", Self::get_name, Default::default()),
JavaMethodProto::new("isAssignableFrom", "(Ljava/lang/Class;)Z", Self::is_assignable_from, Default::default()),
JavaMethodProto::new(
"getResourceAsStream",
"(Ljava/lang/String;)Ljava/io/InputStream;",
Self::get_resource_as_stream,
Default::default(),
),
JavaMethodProto::new(
"forName",
"(Ljava/lang/String;)Ljava/lang/Class;",
Self::for_name,
MethodAccessFlags::STATIC,
),
],
fields: vec![
// Stored as raw bytes instead of java/lang/String to avoid circular dependency:
// from_rust_class -> JavaLangString::from_rust_string -> new_class("java/lang/String") -> from_rust_class -> stack overflow
JavaFieldProto::new("nameBytes", "[B", Default::default()),
JavaFieldProto::new("classLoader", "Ljava/lang/ClassLoader;", Default::default()),
],
access_flags: Default::default(),
}
}
async fn init(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
tracing::debug!("java.lang.Class::<init>({:?})", &this);
let _: () = jvm.invoke_special(&this, "java/lang/Object", "<init>", "()V", ()).await?;
Ok(())
}
async fn get_name(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<String>> {
tracing::debug!("java.lang.Class::getName({:?})", &this);
let rust_class = JavaLangClass::to_rust_class(jvm, &this).await?;
let result = JavaLangString::from_rust_string(jvm, &rust_class.name()).await?;
Ok(result.into())
}
async fn is_assignable_from(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, other: ClassInstanceRef<Self>) -> Result<bool> {
tracing::debug!("java.lang.Class::isAssignableFrom({:?}, {:?})", &this, &other);
let rust_class = JavaLangClass::to_rust_class(jvm, &this).await?;
let other_rust_class = JavaLangClass::to_rust_class(jvm, &other).await?;
Ok(jvm.is_inherited_from(&*other_rust_class, &rust_class.name()))
}
async fn get_resource_as_stream(
jvm: &Jvm,
_context: &mut RuntimeContext,
this: ClassInstanceRef<Self>,
name: ClassInstanceRef<String>,
) -> Result<ClassInstanceRef<InputStream>> {
tracing::debug!("java.lang.Class::getResourceAsStream({:?}, {:?})", &this, &name);
let class_loader: ClassInstanceRef<ClassLoader> = jvm.get_field(&this, "classLoader", "Ljava/lang/ClassLoader;").await?;
let class_loader = if class_loader.is_null() {
// TODO ClassLoader.getSystemResourceAsStream?
JavaLangClassLoader::get_system_class_loader(jvm).await?
} else {
class_loader.into()
};
jvm.invoke_virtual(&class_loader, "getResourceAsStream", "(Ljava/lang/String;)Ljava/io/InputStream;", (name,))
.await
}
async fn for_name(jvm: &Jvm, _context: &mut RuntimeContext, name: ClassInstanceRef<String>) -> Result<ClassInstanceRef<Class>> {
tracing::debug!("java.lang.Class::forName({:?})", &name);
let rust_name = JavaLangString::to_rust_string(jvm, &name).await?;
let qualified_name = rust_name.replace('.', "/");
let class = jvm.get_class(&qualified_name).unwrap().java_class();
Ok(class.into())
}
}