| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| part of dart_jni; |
| |
| class JavaError extends Error { |
| JavaError(this._message); |
| String _message; |
| String toString() => _message; |
| } |
| |
| // JNI methods used to invoke Java reflection |
| class _JavaReflect { |
| JniClass classClazz; |
| int classForName; |
| int classGetConstructors; |
| int classGetFields; |
| int classGetMethods; |
| int classGetName; |
| int constructorGetParameterTypes; |
| int fieldGetType; |
| int memberGetModifiers; |
| int memberGetName; |
| int methodGetParameterTypes; |
| int methodGetReturnType; |
| int objectGetClass; |
| int objectToString; |
| JniClass stringClazz; |
| |
| int modifierStatic; |
| |
| _JavaReflect() { |
| classClazz = JniClass.fromName('java.lang.Class'); |
| classForName = classClazz.getStaticMethodId('forName', |
| '(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;'); |
| classGetConstructors = classClazz.getMethodId('getConstructors', |
| '()[Ljava/lang/reflect/Constructor;'); |
| classGetFields = classClazz.getMethodId('getFields', '()[Ljava/lang/reflect/Field;'); |
| classGetMethods = classClazz.getMethodId('getMethods', '()[Ljava/lang/reflect/Method;'); |
| classGetName = classClazz.getMethodId('getName', '()Ljava/lang/String;'); |
| |
| JniClass constructorClazz = JniClass.fromName('java.lang.reflect.Constructor'); |
| constructorGetParameterTypes = constructorClazz.getMethodId( |
| 'getParameterTypes', '()[Ljava/lang/Class;'); |
| |
| JniClass fieldClazz = JniClass.fromName('java.lang.reflect.Field'); |
| fieldGetType = fieldClazz.getMethodId('getType', '()Ljava/lang/Class;'); |
| |
| JniClass memberClazz = JniClass.fromName('java.lang.reflect.Member'); |
| memberGetModifiers = memberClazz.getMethodId('getModifiers', '()I'); |
| memberGetName = memberClazz.getMethodId('getName', '()Ljava/lang/String;'); |
| |
| JniClass methodClazz = JniClass.fromName('java.lang.reflect.Method'); |
| methodGetParameterTypes = methodClazz.getMethodId( |
| 'getParameterTypes', '()[Ljava/lang/Class;'); |
| methodGetReturnType = methodClazz.getMethodId( |
| 'getReturnType', '()Ljava/lang/Class;'); |
| |
| JniClass modifierClazz = JniClass.fromName('java.lang.reflect.Modifier'); |
| modifierStatic = modifierClazz.getStaticIntField( |
| modifierClazz.getStaticFieldId('STATIC', 'I')); |
| |
| JniClass objectClazz = JniClass.fromName('java.lang.Object'); |
| objectGetClass = objectClazz.getMethodId('getClass', '()Ljava/lang/Class;'); |
| objectToString = objectClazz.getMethodId('toString', '()Ljava/lang/String;'); |
| |
| stringClazz = JniClass.fromName('java.lang.String'); |
| } |
| } |
| |
| final _JavaReflect _reflect = new _JavaReflect(); |
| |
| class _JavaType { |
| final String name; |
| final JniClass clazz; |
| final bool isPrimitive; |
| |
| _JavaType(this.name, this.clazz) |
| : isPrimitive = false; |
| |
| _JavaType._primitive(this.name) |
| : clazz = null, |
| isPrimitive = true; |
| |
| String toString() => 'JavaType:$name'; |
| } |
| |
| class _JavaPrimitive { |
| static final _JavaType jvoid = new _JavaType._primitive('void'); |
| static final _JavaType jboolean = new _JavaType._primitive('boolean'); |
| static final _JavaType jbyte = new _JavaType._primitive('byte'); |
| static final _JavaType jchar = new _JavaType._primitive('char'); |
| static final _JavaType jshort = new _JavaType._primitive('short'); |
| static final _JavaType jint = new _JavaType._primitive('int'); |
| static final _JavaType jlong = new _JavaType._primitive('long'); |
| static final _JavaType jfloat = new _JavaType._primitive('float'); |
| static final _JavaType jdouble = new _JavaType._primitive('double'); |
| } |
| |
| final Map<String, _JavaType> _typeCache = <String, _JavaType>{ |
| 'void': _JavaPrimitive.jvoid, |
| 'boolean': _JavaPrimitive.jboolean, |
| 'byte': _JavaPrimitive.jbyte, |
| 'char': _JavaPrimitive.jchar, |
| 'short': _JavaPrimitive.jshort, |
| 'int': _JavaPrimitive.jint, |
| 'long': _JavaPrimitive.jlong, |
| 'float': _JavaPrimitive.jfloat, |
| 'double': _JavaPrimitive.jdouble, |
| }; |
| |
| _JavaType _javaTypeForClass(JniClass clazz) { |
| String className = JniString.unwrap(clazz.callObjectMethod(_reflect.classGetName, [])); |
| |
| _JavaType type = _typeCache[className]; |
| if (type != null) |
| return type; |
| |
| type = new _JavaType(className, clazz); |
| _typeCache[className] = type; |
| return type; |
| } |
| |
| class _JavaField { |
| String name; |
| int fieldId; |
| _JavaType type; |
| int modifiers; |
| |
| _JavaField(JniObject field) { |
| name = JniString.unwrap(field.callObjectMethod(_reflect.memberGetName, [])); |
| fieldId = JniApi.fromReflectedField(field); |
| type = _javaTypeForClass( |
| field.callObjectMethod(_reflect.fieldGetType, [])); |
| modifiers = field.callIntMethod(_reflect.memberGetModifiers, []); |
| } |
| |
| bool get isStatic => (modifiers & _reflect.modifierStatic) != 0; |
| } |
| |
| abstract class _HasArguments { |
| String get name; |
| List<_JavaType> get argTypes; |
| int get methodId; |
| } |
| |
| class _JavaMethod implements _HasArguments { |
| String _name; |
| int _methodId; |
| _JavaType returnType; |
| int modifiers; |
| List<_JavaType> _argTypes; |
| |
| _JavaMethod(JniObject method) { |
| _name = JniString.unwrap(method.callObjectMethod(_reflect.memberGetName, [])); |
| _methodId = JniApi.fromReflectedMethod(method); |
| returnType = _javaTypeForClass( |
| method.callObjectMethod(_reflect.methodGetReturnType, [])); |
| modifiers = method.callIntMethod(_reflect.memberGetModifiers, []); |
| |
| JniObjectArray argClasses = method.callObjectMethod(_reflect.methodGetParameterTypes, []); |
| _argTypes = new List<_JavaType>(); |
| for (JniObject argClass in argClasses) { |
| _argTypes.add(_javaTypeForClass(argClass)); |
| } |
| } |
| |
| String get name => _name; |
| List<_JavaType> get argTypes => _argTypes; |
| int get methodId => _methodId; |
| |
| bool get isStatic => (modifiers & _reflect.modifierStatic) != 0; |
| } |
| |
| class _JavaConstructor implements _HasArguments { |
| String _name; |
| int _methodId; |
| List<_JavaType> _argTypes; |
| |
| _JavaConstructor(JniObject ctor) { |
| _name = JniString.unwrap(ctor.callObjectMethod(_reflect.memberGetName, [])); |
| _methodId = JniApi.fromReflectedMethod(ctor); |
| |
| JniObjectArray argClasses = ctor.callObjectMethod( |
| _reflect.constructorGetParameterTypes, []); |
| _argTypes = new List<_JavaType>(); |
| for (JniObject argClass in argClasses) { |
| _argTypes.add(_javaTypeForClass(argClass)); |
| } |
| } |
| |
| String get name => _name; |
| List<_JavaType> get argTypes => _argTypes; |
| int get methodId => _methodId; |
| } |
| |
| // Determines whether a Dart value can be used as a method argument declared as |
| // the given Java type. |
| bool _typeCompatible(dynamic value, _JavaType type) { |
| if (type.isPrimitive) { |
| if (type == _JavaPrimitive.jboolean) { |
| return (value is bool); |
| } else { |
| return (value is num || value is bool || value is JniFloat); |
| } |
| } |
| |
| if (value == null) |
| return true; |
| |
| if (value is JavaObject) |
| return value.javaClass.jniClass.isAssignable(type.clazz); |
| |
| if (value is JniObject) |
| return value.getObjectClass().isAssignable(type.clazz); |
| |
| if (value is String) { |
| if (type.isPrimitive) |
| return false; |
| return _reflect.stringClazz.isAssignable(type.clazz); |
| } |
| |
| return false; |
| } |
| |
| // Given a list of overloaded methods, select one that is the best match for |
| // the provided arguments. |
| _HasArguments _findMatchingMethod(List<_HasArguments> overloads, List args) { |
| List<_HasArguments> matches = new List<_HasArguments>(); |
| for (_HasArguments overload in overloads) { |
| if (overload.argTypes.length == args.length) |
| matches.add(overload); |
| } |
| |
| if (matches.length == 1) |
| return matches[0]; |
| |
| if (matches.isEmpty) |
| throw new JavaError('Argument mismatch when invoking method ${overloads[0].name}'); |
| |
| outer: for (_HasArguments match in matches) { |
| for (int i = 0; i < args.length; i++) { |
| if (!_typeCompatible(args[i], match.argTypes[i])) |
| continue outer; |
| } |
| return match; |
| } |
| |
| throw new JavaError('Unable to find matching method for ${overloads[0].name}'); |
| } |
| |
| // Convert an object received from JNI into the corresponding Dart type. |
| dynamic _javaObjectToDart(JniObject object) { |
| if (object == null) |
| return null; |
| |
| if (object is JniString) |
| return object.text; |
| |
| if (object is JniClass) |
| return Java.wrapClassObject(object); |
| |
| if (object is JniArray) |
| return object; |
| |
| return new JavaObject(object); |
| } |
| |
| // Convert a Dart object to a type suitable for passing to JNI. |
| dynamic _dartObjectToJava(dynamic object, _JavaType javaType) { |
| if (javaType.isPrimitive) { |
| if (javaType == _JavaPrimitive.jboolean) { |
| if (object is bool) |
| return object; |
| throw new JavaError('Unable to convert Dart object to Java boolean: $object'); |
| } |
| if (javaType == _JavaPrimitive.jfloat) { |
| if (object is JniFloat) |
| return object; |
| if (object is num) |
| return new JniFloat(object); |
| throw new JavaError('Unable to convert Dart object to Java float: $object'); |
| } |
| |
| if (object is num) |
| return object; |
| throw new JavaError('Unable to convert Dart object to Java primitive type: $object'); |
| } |
| |
| if (object == null) |
| return object; |
| |
| if (object is JniObject) |
| return object; |
| |
| if (object is JavaObject) |
| return object.jniObject; |
| |
| if (object is String) |
| return JniString.create(object); |
| |
| throw new JavaError('Unable to convert Dart object to Java: $object'); |
| } |
| |
| List _convertArgumentsToJava(List dartArgs, _HasArguments method) { |
| List result = new List(); |
| for (int i = 0; i < dartArgs.length; i++) { |
| result.add(_dartObjectToJava(dartArgs[i], method.argTypes[i])); |
| } |
| return result; |
| } |
| |
| /// A class that provides access to Java objects from within Dart. |
| class Java { |
| static final Map<String, JavaClass> _classCache = new Map<String, JavaClass>(); |
| |
| /// Returns a [JavaClass] for the given class name. |
| static JavaClass getClass(String className) { |
| JavaClass cacheEntry = _classCache[className]; |
| if (cacheEntry != null) |
| return cacheEntry; |
| |
| // Load and initialize the class |
| JniClass jniClass = _reflect.classClazz.callStaticObjectMethod( |
| _reflect.classForName, |
| [className, true, JniApi.getClassLoader()] |
| ); |
| |
| JavaClass javaClass = new JavaClass._(jniClass); |
| _classCache[javaClass.className] = javaClass; |
| return javaClass; |
| } |
| |
| /// Returns a [JavaClass] that wraps a raw JNI class object. |
| static JavaClass wrapClassObject(dynamic classObject) { |
| JniClass jniClass; |
| if (classObject is JniClass) { |
| jniClass = classObject; |
| } else if (classObject is JavaObject && classObject.jniObject is JniClass) { |
| jniClass = classObject.jniObject; |
| } else { |
| throw new JavaError('fromClassObject: $classObject is not a Java class'); |
| } |
| |
| String className = JniString.unwrap(jniClass.callObjectMethod(_reflect.classGetName, [])); |
| JavaClass cacheEntry = _classCache[className]; |
| if (cacheEntry != null) |
| return cacheEntry; |
| |
| JavaClass javaClass = new JavaClass._(jniClass); |
| _classCache[javaClass.className] = javaClass; |
| return javaClass; |
| } |
| } |
| |
| /// A wrapper for a JNI class that uses reflection to provide access to the |
| /// class' static fields, methods, and constructors. |
| class JavaClass { |
| JniClass _clazz; |
| String _className; |
| Map<Symbol, _JavaField> _fields; |
| Map<Symbol, _JavaField> _staticFields; |
| Map<Symbol, List<_JavaMethod>> _methods; |
| Map<Symbol, List<_JavaMethod>> _staticMethods; |
| List<_JavaConstructor> _constructors; |
| |
| static final Symbol _newInstanceSymbol = new Symbol('newInstance'); |
| |
| JavaClass._(JniClass classObject) { |
| _clazz = classObject; |
| _className = JniString.unwrap(_clazz.callObjectMethod(_reflect.classGetName, [])); |
| |
| _fields = new Map<Symbol, _JavaField>(); |
| _staticFields = new Map<Symbol, _JavaField>(); |
| JniObjectArray reflectFields = _clazz.callObjectMethod(_reflect.classGetFields, []); |
| for (JniObject reflectField in reflectFields) { |
| _JavaField javaField = new _JavaField(reflectField); |
| Map<Symbol, _JavaField> fieldMap = |
| javaField.isStatic ? _staticFields : _fields; |
| fieldMap[new Symbol(javaField.name)] = javaField; |
| |
| // Dart will identify the field setter with a symbol name ending with an equal sign. |
| fieldMap[new Symbol(javaField.name + '=')] = javaField; |
| } |
| |
| _methods = new Map<Symbol, List<_JavaMethod>>(); |
| _staticMethods = new Map<Symbol, List<_JavaMethod>>(); |
| JniObjectArray reflectMethods = _clazz.callObjectMethod(_reflect.classGetMethods, []); |
| for (JniObject reflectMethod in reflectMethods) { |
| _JavaMethod javaMethod = new _JavaMethod(reflectMethod); |
| Map<Symbol, List<_JavaMethod>> methodMap = |
| javaMethod.isStatic ? _staticMethods : _methods; |
| Symbol symbol = new Symbol(javaMethod.name); |
| List<_JavaMethod> overloads = methodMap[symbol]; |
| if (overloads != null) { |
| overloads.add(javaMethod); |
| } else { |
| methodMap[symbol] = <_JavaMethod>[javaMethod]; |
| } |
| } |
| |
| _constructors = new List<_JavaConstructor>(); |
| JniObjectArray reflectCtors = _clazz.callObjectMethod(_reflect.classGetConstructors, []); |
| for (JniObject ctor in reflectCtors) { |
| _constructors.add(new _JavaConstructor(ctor)); |
| } |
| } |
| |
| String toString() => 'JavaClass:$_className'; |
| |
| /// The name of the wrapped Java class. |
| String get className => _className; |
| |
| /// A raw [JniClass] representing the java.lang.Class instance for this class |
| JniClass get jniClass => _clazz; |
| |
| /// A [JavaObject] representing the java.lang.Class instance for this class |
| JavaObject get asJavaObject => new JavaObject(_clazz); |
| |
| dynamic noSuchMethod(Invocation invocation) { |
| if (invocation.isMethod) { |
| List<_HasArguments> overloads; |
| bool isConstructor = (invocation.memberName == _newInstanceSymbol); |
| if (isConstructor) { |
| overloads = _constructors; |
| } else { |
| overloads = _staticMethods[invocation.memberName]; |
| if (overloads == null) |
| throw new JavaError('Static method ${invocation.memberName} not found'); |
| } |
| |
| _HasArguments method = _findMatchingMethod(overloads, invocation.positionalArguments); |
| List args = _convertArgumentsToJava(invocation.positionalArguments, method); |
| |
| if (isConstructor) { |
| return new JavaObject(_clazz.newObject(method.methodId, args)); |
| } |
| |
| _JavaType returnType = (method as _JavaMethod).returnType; |
| if (returnType == _JavaPrimitive.jvoid) { |
| return _clazz.callStaticVoidMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jboolean) { |
| return _clazz.callStaticBooleanMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jbyte) { |
| return _clazz.callStaticByteMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jchar) { |
| return _clazz.callStaticCharMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jshort) { |
| return _clazz.callStaticShortMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jint) { |
| return _clazz.callStaticIntMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jlong) { |
| return _clazz.callStaticLongMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jfloat) { |
| return _clazz.callStaticFloatMethod(method.methodId, args); |
| } else if (returnType == _JavaPrimitive.jdouble) { |
| return _clazz.callStaticDoubleMethod(method.methodId, args); |
| } else { |
| return _javaObjectToDart( |
| _clazz.callStaticObjectMethod(method.methodId, args)); |
| } |
| } |
| |
| if (invocation.isGetter) { |
| _JavaField field = _staticFields[invocation.memberName]; |
| if (field == null) |
| throw new JavaError('Static field ${invocation.memberName} not found'); |
| |
| if (field.type == _JavaPrimitive.jboolean) { |
| return _clazz.getStaticBooleanField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jbyte) { |
| return _clazz.getStaticByteField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jchar) { |
| return _clazz.getStaticCharField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jshort) { |
| return _clazz.getStaticShortField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jint) { |
| return _clazz.getStaticIntField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jlong) { |
| return _clazz.getStaticLongField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jfloat) { |
| return _clazz.getStaticFloatField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jdouble) { |
| return _clazz.getStaticDoubleField(field.fieldId); |
| } else { |
| return _javaObjectToDart(_clazz.getStaticObjectField(field.fieldId)); |
| } |
| } |
| |
| if (invocation.isSetter) { |
| _JavaField field = _staticFields[invocation.memberName]; |
| if (field == null) |
| throw new JavaError('Static field ${invocation.memberName} not found'); |
| |
| dynamic value = invocation.positionalArguments[0]; |
| |
| if (field.type == _JavaPrimitive.jboolean) { |
| _clazz.setStaticBooleanField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jbyte) { |
| _clazz.setStaticByteField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jchar) { |
| _clazz.setStaticCharField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jshort) { |
| _clazz.setStaticShortField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jint) { |
| _clazz.setStaticIntField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jlong) { |
| _clazz.setStaticLongField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jfloat) { |
| _clazz.setStaticFloatField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jdouble) { |
| _clazz.setStaticDoubleField(field.fieldId, value); |
| } else { |
| _clazz.setStaticObjectField(field.fieldId, _dartObjectToJava(value, field.type)); |
| } |
| |
| return null; |
| } |
| |
| throw new JavaError('Unable to access ${invocation.memberName}'); |
| } |
| } |
| |
| /// A wrapper for a JNI object that provides access to the object's fields |
| /// and methods. |
| class JavaObject { |
| JniObject _object; |
| JavaClass _clazz; |
| |
| JavaObject(JniObject object) { |
| _object = object; |
| |
| _clazz = Java.wrapClassObject( |
| _object.callObjectMethod(_reflect.objectGetClass, [])); |
| } |
| |
| dynamic noSuchMethod(Invocation invocation) { |
| if (invocation.isMethod) { |
| List<_JavaMethod> overloads = _clazz._methods[invocation.memberName]; |
| if (overloads == null) |
| throw new JavaError('Method ${invocation.memberName} not found'); |
| |
| _JavaMethod method = _findMatchingMethod(overloads, invocation.positionalArguments); |
| List args = _convertArgumentsToJava(invocation.positionalArguments, method); |
| |
| if (method.returnType == _JavaPrimitive.jvoid) { |
| return _object.callVoidMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jboolean) { |
| return _object.callBooleanMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jbyte) { |
| return _object.callByteMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jchar) { |
| return _object.callCharMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jshort) { |
| return _object.callShortMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jint) { |
| return _object.callIntMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jlong) { |
| return _object.callLongMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jfloat) { |
| return _object.callFloatMethod(method.methodId, args); |
| } else if (method.returnType == _JavaPrimitive.jdouble) { |
| return _object.callDoubleMethod(method.methodId, args); |
| } else { |
| return _javaObjectToDart( |
| _object.callObjectMethod(method.methodId, args)); |
| } |
| } |
| |
| if (invocation.isGetter) { |
| _JavaField field = _clazz._fields[invocation.memberName]; |
| if (field == null) |
| throw new JavaError('Field ${invocation.memberName} not found'); |
| |
| if (field.type == _JavaPrimitive.jboolean) { |
| return _object.getBooleanField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jbyte) { |
| return _object.getByteField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jchar) { |
| return _object.getCharField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jshort) { |
| return _object.getShortField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jint) { |
| return _object.getIntField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jlong) { |
| return _object.getLongField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jfloat) { |
| return _object.getFloatField(field.fieldId); |
| } else if (field.type == _JavaPrimitive.jdouble) { |
| return _object.getDoubleField(field.fieldId); |
| } else { |
| return _javaObjectToDart(_object.getObjectField(field.fieldId)); |
| } |
| } |
| |
| if (invocation.isSetter) { |
| _JavaField field = _clazz._fields[invocation.memberName]; |
| if (field == null) |
| throw new JavaError('Field ${invocation.memberName} not found'); |
| |
| dynamic value = invocation.positionalArguments[0]; |
| |
| if (field.type == _JavaPrimitive.jboolean) { |
| _object.setBooleanField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jbyte) { |
| _object.setByteField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jchar) { |
| _object.setCharField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jshort) { |
| _object.setShortField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jint) { |
| _object.setIntField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jlong) { |
| _object.setLongField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jfloat) { |
| _object.setFloatField(field.fieldId, value); |
| } else if (field.type == _JavaPrimitive.jdouble) { |
| _object.setDoubleField(field.fieldId, value); |
| } else { |
| _object.setObjectField(field.fieldId, _dartObjectToJava(value, field.type)); |
| } |
| |
| return null; |
| } |
| |
| throw new JavaError('Unable to access ${invocation.memberName}'); |
| } |
| |
| /// Convert this object to a string using the Java object's `toString` method. |
| String toString() { |
| String result = JniString.unwrap(_object.callObjectMethod(_reflect.objectToString, [])); |
| if (!result.isEmpty) { |
| return result; |
| } else { |
| return 'JavaObject(${_clazz.className})'; |
| } |
| } |
| |
| /// A [JavaClass] representing this object's class. |
| JavaClass get javaClass => _clazz; |
| |
| /// The raw [JniObject] wrapped by this object. |
| /// This can be used to perform low-level JNI operations that aren't exposed |
| /// by [JavaObject], such as access to specific overloaded methods. |
| JniObject get jniObject => _object; |
| } |