Skip to main content

jni_bindgen_reflection/
method.rs

1//! [Java SE 7 § 4.6](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6):  Parsing APIs and structures for class methods.
2
3use crate::*;
4use crate::io::*;
5pub use field::BasicType;
6pub use field::Descriptor as Type;
7
8use bitflags::bitflags;
9
10use std::io::{self, Read};
11
12
13
14bitflags! {
15    #[derive(Default)]
16    /// [Java SE 7 § 4.6](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6):  method_info::access_flags values.
17    pub struct Flags : u16 {
18        /// Declared `public`; may be accessed from outside its package.
19        const PUBLIC        = 0x0001;
20        /// Declared `private`; usable only with the defining class.
21        const PRIVATE       = 0x0002;
22        /// Declared `protectdd`; may be accessed within subclasses.
23        const PROTECTED     = 0x0004;
24        /// Declared `static`.
25        const STATIC        = 0x0008;
26        /// Declared `final`; no subclasses allowed.
27        const FINAL         = 0x0010;
28        /// Declared `syncronized`; invocation is wrapped by a monitor use.
29        const SYNCRONIZED   = 0x0020;
30        /// A bridge method, generated by the compiler.
31        const BRIDGE        = 0x0040;
32        /// Declared with variable number of arguments.
33        const VARARGS       = 0x0080;
34        /// Declared `native`; implemented in a langauge other than Java.
35        const NATIVE        = 0x0100;
36        /// Declared `abstract`; must not be instantiated.
37        const ABSTRACT      = 0x0400;
38        /// Declared `strictfp`; floating-point mode is FP-strict.
39        const STRICT        = 0x0800;
40        /// Declared synthetic; not present in the source code.
41        const SYNTHETIC     = 0x1000;
42    }
43}
44
45impl Flags {
46    pub fn read(r: &mut impl Read) -> io::Result<Self> {
47        Ok(Self::from_bits_truncate(read_u2(r)?))
48    }
49}
50
51
52
53/// [Java SE 7 &sect; 4.6](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6):  method_info, minus the trailing attributes
54#[derive(Clone, Debug)]
55pub struct Method {
56    pub flags:      Flags,
57    pub name:       String,
58    descriptor:     String,
59    pub deprecated: bool,
60    _incomplete:    (),
61}
62
63#[allow(dead_code)]
64impl Method {
65    pub fn new(flags: Flags, name: String, descriptor: String) -> io::Result<Self> {
66        method::Descriptor::new(descriptor.as_str())?;
67        Ok(Self {
68            flags,
69            name,
70            descriptor,
71            deprecated: false,
72            _incomplete: (),
73        })
74    }
75
76    pub fn descriptor_str(&self) -> &str { self.descriptor.as_str() }
77    pub fn descriptor(&self) -> Descriptor { Descriptor::new(self.descriptor.as_str()).unwrap() } // Already validated in new/read_one
78
79    pub fn is_public        (&self) -> bool { self.flags.contains(Flags::PUBLIC         ) }
80    pub fn is_private       (&self) -> bool { self.flags.contains(Flags::PRIVATE        ) }
81    pub fn is_protected     (&self) -> bool { self.flags.contains(Flags::PROTECTED      ) }
82    pub fn is_static        (&self) -> bool { self.flags.contains(Flags::STATIC         ) }
83    pub fn is_final         (&self) -> bool { self.flags.contains(Flags::FINAL          ) }
84    pub fn is_syncronized   (&self) -> bool { self.flags.contains(Flags::SYNCRONIZED    ) }
85    pub fn is_bridge        (&self) -> bool { self.flags.contains(Flags::BRIDGE         ) }
86    pub fn is_varargs       (&self) -> bool { self.flags.contains(Flags::VARARGS        ) }
87    pub fn is_native        (&self) -> bool { self.flags.contains(Flags::NATIVE         ) }
88    pub fn is_abstract      (&self) -> bool { self.flags.contains(Flags::ABSTRACT       ) }
89    pub fn is_strict        (&self) -> bool { self.flags.contains(Flags::STRICT         ) }
90    pub fn is_synthetic     (&self) -> bool { self.flags.contains(Flags::SYNTHETIC      ) }
91
92    pub fn is_constructor   (&self) -> bool { self.name == "<init>" }
93    pub fn is_static_init   (&self) -> bool { self.name == "<clinit>" }
94
95    pub fn access(&self) -> Option<&'static str> {
96        if      self.is_private()   { Some("private") }
97        else if self.is_protected() { Some("protected") }
98        else if self.is_public()    { Some("public") }
99        else                        { None }
100    }
101
102    pub(crate) fn read_one(read: &mut impl Read, constants: &Constants) -> io::Result<Self> {
103        let flags               = Flags::read(read)?;
104        let name                = constants.get_utf8(read_u2(read)?)?.to_owned();
105        let descriptor          = constants.get_utf8(read_u2(read)?)?.to_owned();
106        let attributes_count    = read_u2(read)? as usize;
107
108        method::Descriptor::new(descriptor.as_str())?;
109
110        let mut deprecated      = false;
111        for _ in 0..attributes_count {
112            match Attribute::read(read, constants)? {
113                Attribute::Deprecated { .. } => { deprecated = true; },
114                _ => {},
115            }
116        }
117
118        Ok(Self{
119            flags,
120            name,
121            descriptor,
122            deprecated,
123            _incomplete:    (),
124        })
125    }
126
127    pub(crate) fn read_list(read: &mut impl Read, constants: &Constants) -> io::Result<Vec<Self>> {
128        let n = read_u2(read)? as usize;
129        let mut methods = Vec::with_capacity(n);
130        for _ in 0..n {
131            methods.push(Self::read_one(read, constants)?);
132        }
133        Ok(methods)
134    }
135}
136
137
138
139#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
140pub struct Descriptor<'a> {
141    string:     &'a str,
142    end_paren:  usize,
143}
144
145impl<'a> Descriptor<'a> {
146    pub fn new(desc: &'a str) -> io::Result<Descriptor<'a>> {
147        if !desc.starts_with('(') { return io_data_err!("Method descriptor didn't start with '(': {:?}", desc); }
148        let end_paren = if let Some(i) = desc.rfind(')') { i } else { return io_data_err!("Method descriptor doesn't contain a ')' terminating the arguments list: {:?}", desc); };
149        let (arguments, return_) = desc.split_at(end_paren);
150
151        Type::from_str(&return_[1..])?; // Skip )
152        let mut args = &arguments[1..];  // Skip (
153        while !args.is_empty() {
154            Type::read_next(&mut args)?;
155        }
156
157        Ok(Descriptor { string: desc, end_paren })
158    }
159
160    #[allow(dead_code)]
161    pub fn as_str(&self) -> &'a str { self.string }
162    pub fn return_type(&self) -> Type<'a> { Type::from_str(&self.string[(1+self.end_paren)..]).unwrap() } // Already validated in Descriptor::new
163    pub fn arguments(&self) -> ArgumentsIter { ArgumentsIter(&self.string[1..self.end_paren]) }
164}
165
166pub struct ArgumentsIter<'a>(&'a str);
167
168impl<'a> Iterator for ArgumentsIter<'a> {
169    type Item = Type<'a>;
170    fn next(&mut self) -> Option<Self::Item> {
171        if self.0.is_empty() {
172            None
173        } else {
174            Some(Type::read_next(&mut self.0).unwrap()) // Already verified in Descriptor::next
175        }
176    }
177}
178
179#[test] fn jni_descriptor_from_str() {
180    let d = Descriptor::new("(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;").unwrap();
181    assert_eq!(d.return_type(), Type::Single(BasicType::Class(class::Id("android/database/Cursor"))));
182    let mut d = d.arguments();
183    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/net/Uri")))));
184    assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
185    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
186    assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
187    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
188    assert_eq!(d.next(), None);
189    assert_eq!(d.next(), None);
190
191    let d = Descriptor::new("(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/database/Cursor;").unwrap();
192    assert_eq!(d.return_type(), Type::Single(BasicType::Class(class::Id("android/database/Cursor"))));
193    let mut d = d.arguments();
194    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/net/Uri")))));
195    assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
196    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
197    assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
198    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("java/lang/String")))));
199    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/os/CancellationSignal")))));
200    assert_eq!(d.next(), None);
201    assert_eq!(d.next(), None);
202
203    let d = Descriptor::new("(Landroid/net/Uri;[Ljava/lang/String;Landroid/os/Bundle;Landroid/os/CancellationSignal;)Landroid/database/Cursor;").unwrap();
204    assert_eq!(d.return_type(), Type::Single(BasicType::Class(class::Id("android/database/Cursor"))));
205    let mut d = d.arguments();
206    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/net/Uri")))));
207    assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
208    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/os/Bundle")))));
209    assert_eq!(d.next(), Some(Type::Single(BasicType::Class(class::Id("android/os/CancellationSignal")))));
210    assert_eq!(d.next(), None);
211    assert_eq!(d.next(), None);
212
213    let d = Descriptor::new("([Ljava/lang/String;)V").unwrap();
214    assert_eq!(d.return_type(), Type::Single(BasicType::Void));
215    let mut d = d.arguments();
216    assert_eq!(d.next(), Some(Type::Array { levels: 1, inner: BasicType::Class(class::Id("java/lang/String")) }));
217    assert_eq!(d.next(), None);
218    assert_eq!(d.next(), None);
219
220    let d = Descriptor::new("()V").unwrap();
221    assert_eq!(d.return_type(), Type::Single(BasicType::Void));
222    let mut d = d.arguments();
223    assert_eq!(d.next(), None);
224    assert_eq!(d.next(), None);
225}