[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/feathr-ai/feathr-online/main/java/src/java_function.rs [Back]  [Original]

use jni::{
    objects::{GlobalRef, JList, JMethodID, JObject, JValue},
    sys::jvalue,
    JNIEnv,
};

use crate::{get_jvm, to_jvalue, to_string, to_value};

#[derive(Clone)]
pub struct JavaFunction {
    pub obj: GlobalRef,
    pub method_id: JMethodID,
    pub arity: Option,
}

impl JavaFunction {
    pub fn new(env: &JNIEnv, obj: JObject) -> Result {
        let obj = env.new_global_ref(obj).unwrap();

        // Check from Function0 to Function'MAX_ARITY'
        for a in 0..get_jvm().max_arity {
            let cls = env
                .find_class(format!("com/linkedin/feathr/online/Function{a}"))
                .map_err(|e| piper::PiperError::ExternalError(e.to_string()))?;
            if env
                .is_instance_of(&obj, cls)
                .map_err(|e| piper::PiperError::ExternalError(e.to_string()))?
            {
                let method_id = env
                    .get_method_id(
                        cls,
                        format!("apply{a}"),
                        format!("({})Ljava/lang/Object;", "Ljava/lang/Object;".repeat(a)),
                    )
                    .map_err(|e| piper::PiperError::ExternalError(e.to_string()))?;
                return Ok(Self {
                    obj,
                    method_id,
                    arity: Some(a),
                });
            }
        }

        // Assume VarFunction
        let cls = env
            .find_class("com/azure/feathr/piper/VarFunction")
            .map_err(|e| piper::PiperError::ExternalError(e.to_string()))?;
        let method_id = env
            .get_method_id(cls, "applyVar", "([Ljava/lang/Object;)Ljava/lang/Object;")
            .map_err(|e| piper::PiperError::ExternalError(e.to_string()))?;
        Ok(Self {
            obj,
            method_id,
            arity: None,
        })
    }
}

impl piper::Function for JavaFunction {
    fn get_output_type(
        &self,
        _argument_types: &[piper::ValueType],
    ) -> Result {
        Ok(piper::ValueType::Dynamic)
    }

    fn eval(&self, arguments: Vec) -> piper::Value {
        let env = match get_jvm().jvm.attach_current_thread_as_daemon() {
            Ok(env) => env,
            Err(e) => return piper::Value::Error(piper::PiperError::ExternalError(e.to_string())),
        };

        let args: Vec = match self.arity {
            None => {
                // call applyVar
                let array_list_cls = &get_jvm().array_list_cls;
                let new_array_list = get_jvm().new_array_list;
                let l = env
                    .new_object_unchecked(array_list_cls, new_array_list, &[])
                    .unwrap();
                let j = JList::from_env(&env, l).unwrap();
                for arg in arguments {
                    j.add(to_jvalue(arg, &env)).unwrap();
                }
                let o: JObject = j.into();
                vec![JValue::Object(o).to_jni()]
            }
            Some(arity) => arguments
                .into_iter()
                .take(arity)
                .map(|a| JValue::Object(to_jvalue(a, &env)).to_jni())
                .collect(),
        };

        let ret = env
            .call_method_unchecked(
                self.obj.as_obj(),
                self.method_id,
                jni::signature::ReturnType::Object,
                &args,
            )
            .map_err(|e| piper::PiperError::ExternalError(e.to_string()))
            .and_then(|v| {
                to_value(v, &env).map_err(|e| piper::PiperError::ExternalError(e.to_string()))
            });
        if ret.is_err() {
            match env.exception_occurred() {
                Ok(ex) => {
                    if !ex.is_null() {
                        env.exception_clear().unwrap();
                        return piper::PiperError::ExternalError(to_string(&env, ex.into())).into();
                    }
                }
                Err(e) => return piper::PiperError::ExternalError(e.to_string()).into(),
            };
        }
        ret.into()
    }
}

Web Proxy Viewer  |  New URL  |  Original Page