From 8a4bc74b4b9621a694b210efd09e9dfeca104c06 Mon Sep 17 00:00:00 2001 From: Ombuweb Date: Sun, 20 Nov 2022 19:55:57 +0100 Subject: [PATCH 01/14] docs: initial content for Android Marshalling --- .../nativescript-android-marshalling.md | 824 ++++++++++++++++++ content/sidebar.ts | 9 + 2 files changed, 833 insertions(+) create mode 100644 content/guide/marshalling/nativescript-android-marshalling.md diff --git a/content/guide/marshalling/nativescript-android-marshalling.md b/content/guide/marshalling/nativescript-android-marshalling.md new file mode 100644 index 00000000..6253a067 --- /dev/null +++ b/content/guide/marshalling/nativescript-android-marshalling.md @@ -0,0 +1,824 @@ +--- +title: Android Marshalling +--- + +This article looks at how NativeScript handles the conversion between JavaScript data types and Java/Kotlin data types. + +## String Conversion +### Converting JavaScript String to Java string types + +JavaScript [String](http://www.w3schools.com/jsref/jsref_obj_string.asp) maps to [java.lang.String](http://developer.android.com/reference/java/lang/String.html): + +```js +var context = ...; +var button = new android.widget.Button(context); +var text = "My Button"; +button.setText(text); +``` +`button.setText(text)` - `text` is converted to `java.lang.String` + +### Converting JavaScript String to Kotlin string types + +JavaScript [String](http://www.w3schools.com/jsref/jsref_obj_string.asp) maps to [kotlin.String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html): + +```js +var kotlinClass = new com.example.KotlinClassWithStringProperty() +var text = 'My Button' +kotlinClass.setStringProperty(text) / +``` +`kotlinClass.setStringProperty(text)` - JavaScript `text` is converted to `kotlin.String` + +### Converting Java string types to JavaScript String +Both [java.lang.String](http://developer.android.com/reference/java/lang/String.html) and [java.lang.Character](http://docs.oracle.com/javase/7/docs/api/java/lang/Character.html) types are projected as JavaScript [String](http://www.w3schools.com/jsref/jsref_obj_string.asp): + +```js +var file = new java.io.File('/path/to/file') +var path = file.getPath() +``` + +`getPath()` - returns `java.lang.String`, converted to JS `String` + +### Converting Kotlin string types to JavaScript String + +Both [kotlin.String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html) and [kotlin.Char](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-char/index.html) types are projected as JavaScript [String](http://www.w3schools.com/jsref/jsref_obj_string.asp): + +```kotlin +package com.example + +class KotlinClassWithStringAndCharProperty { + val stringProperty: String = "string property" + val charProperty: Char = 'c' +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithStringAndCharProperty() +var str1 = kotlinClass.getStringProperty() // returns kotlin.String, converted to JS String +var str2 = kotlinClass.getCharProperty() // returns kotlin.Char, converted to JS String +``` + +- `getStringProperty()`- returns `kotlin.String`, converted to `JS String` +- `getCharProperty()` - returns `kotlin.Char`, converted to JS `String` + +## Boolean conversion + +### JavaScript Boolean to Java boolean type +JavaScript [Boolean](http://www.w3schools.com/js/js_booleans.asp) maps to Java [primitive boolean](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html). + +```js +var context = ...; +var button = new android.widget.Button(context); +var enabled = false; +button.setEnabled(enabled); +``` + +`button.setEnabled(enabled)` - JavaScript Boolean `enabled` is converted to Java primitive boolean. + +### JavaScript Boolean to Kotlin boolean type +JavaScript [Boolean](http://www.w3schools.com/js/js_booleans.asp) maps to Kotlin class [Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html). + +### Converting from Java boolean to JavaScript boolean + +Both the primitive [boolean](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) and reference [java.lang.Boolean](http://docs.oracle.com/javase/7/docs/api/java/lang/Boolean.html) types are projected as JavaScript [Boolean](http://www.w3schools.com/jsref/jsref_obj_boolean.asp): + +```js +var context = ... +var button = new android.widget.Button(context); +var enabled = button.isEnabled(); +``` + +`isEnabled()` - returns `primitive boolean`, converted to JS `Boolean` + + +### Converting from Kotlin boolean to JavaScript boolean + +Kotlin's boolean type [kotlin.Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) is mapped to JavaScript [Boolean](http://www.w3schools.com/jsref/jsref_obj_boolean.asp): + + +```kotlin +package com.example + +class KotlinClassWithBooleanProperty { + val booleanProperty: Boolean = false +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithBooleanProperty() +var enabled = kotlinClass.getBooleanProperty() // returns Kotlin Boolean, converted to JS Boolean +``` + +`getBooleanProperty()` - returns `Kotlin Boolean`, converted to JS `Boolean`. + + +## Numeric data types + +### Converting JavaScript Number to Java/Kotlin numeric types + +Java and Koltin have several primitive numeric types while JavaScript has the `Number` type only. Additionally, unlike JavaScript, Java and Kotlin support [Method Overloading](http://en.wikipedia.org/wiki/Function_overloading), which makes the numeric conversion more complex. + +Consider the following examples: + +```java +class MyObject extends java.lang.Object { + public void myMethod(byte value){ + } + + public void myMethod(short value){ + } + + public void myMethod(int value){ + } + + public void myMethod(long value){ + } + + public void myMethod(float value){ + } + + public void myMethod(double value){ + } +} +``` + +```kotlin +class MyObject : Any() { + fun myMethod(value: Byte) {} + + fun myMethod(value: Short) {} + + fun myMethod(value: Int) {} + + fun myMethod(value: Long) {} + + fun myMethod(value: Float) {} + + fun myMethod(value: Double) {} +} +``` + +The following logic applies when calling `myMethod` on a `myObject` instance from JavaScript: + +```js +var myObject = new MyObject() +``` +#### Implicit conversion + +- **integer** conversion: + +When you call + +```js +myObject.myMethod(10) +``` + +the runtime implicitly converts the JavaScript `10(Number)` to Java/Kotlin `Int` and then calls the `myMethod(Int)` method. + +::: warning Note +If there is no myMethod(Int) implementation, the Android runtime will try to choose the best possible overload with least conversion loss. If no such method is found an exception will be raised. +::: + +- **floating-point** conversion: + +```js +myObject.myMethod(10.5) // myMethod(Double) will be called. +``` +The JavaScript `10.5` `Number` gets converted to Java/Kotlin `double` and then myMethod(ouble) gets called. + +::: warning Note +If there is no myMethod(double) implementation, the Runtime will try to choose the best possible overload with least conversion loss. If no such method is found an exception will be raised. +::: + +#### Explicit conversion + +To explicitly convert from a JavaScript `Number` to Java/Kotlin numeric data types, and call a specific method overload, NativeScript provides the following functions in the global scope: + +- `byte(number)` → (`Java primitive byte` | `Kotlin Byte` )
+ \- The number value will be truncated and only its first byte of the whole part will be used. +- `short(number)` → Java primitive short + +### Converting Java numeric types to JavaScript Number + +The following Java types are converted to the JavaScript [Number](http://www.w3schools.com/jsref/jsref_obj_number.asp): + +- Primitive [byte](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) and reference [java.lang.Byte](http://docs.oracle.com/javase/7/docs/api/java/lang/Byte.html) : + +```js +var byte = new java.lang.Byte('1') +var jsByteValue = byte.byteValue() // returns primitive byte, converted to Number +``` + +- Primitive [short](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) and reference [java.lang.Short](http://docs.oracle.com/javase/7/docs/api/java/lang/Short.html) : + +```js +var short = new java.lang.Short('1') +var jsShortValue = short.shortValue() // returns primitive short, converted to Number +``` + +- Primitive [int](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) and reference [java.lang.Integer](http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html): + +```js +var int = new java.lang.Integer('1') +var jsIntValue = int.intValue() // returns primitive int, converted to Number +``` +`intValue()` - returns `primitive int`, converted to `Number` +- Primitive [float](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) and reference [java.lang.Float](http://docs.oracle.com/javase/7/docs/api/java/lang/Float.html) : + +```js +var float = new java.lang.Float('1.5') +var jsFloatValue = float.floatValue() // returns primitive float, converted to Number +``` +`floatValue()` returns a `primitive float`, converted to `Number`. + +- Primitive [double](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) and reference [java.lang.Double](http://docs.oracle.com/javase/7/docs/api/java/lang/Double.html) : + +```js +var double = new java.lang.Double('1.5') +var jsDoubleValue = double.doubleValue() // returns primitive double, converted to Number +``` +`doubleValue()` returns a `primitive float`, converted to `Number`. +- Long & Primitive long + +[java.lang.Long](http://docs.oracle.com/javase/7/docs/api/java/lang/Long.html) and its primitive equivalent are special types which are projected to JavaScript by applying the following rules: + + - If the value is in the interval `(-2^53, 2^53)` then it is converted to [Number](http://www.w3schools.com/jsref/jsref_obj_number.asp) + - Else a special object with the following characteristics is created: + - Has Number.NaN set as a prototype + - Has value property set to the string representation of the Java long value + - Its `valueOf()` method returns NaN + - Its `toString()` method returns the string representation of the Java long value + +```java +public class TestClass { + public long getLongNumber54Bits(){ + return 1 << 54; + } + public long getLongNumber53Bits(){ + return 1 << 53; + } +} +``` + +```js +var testClass = new TestClass() +var jsNumber = testClass.getLongNumber53Bits() +var specialObject = testClass.getLongNumber54Bits() +``` + +`jsNumber` is a JavaScript Number and `specialObject` is the special object discussed above. + +### Converting Kotlin numeric types to JavaScript Number + +Similar to the conversion from Java numeric data types to JavaScript Number, the following Kotlin numeric data types are converted to JavaScript Number type: + +- Kotlin's byte type [kotlin.Byte](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-byte/index.html): + + +```kotlin +package com.example + +class KotlinClassWithByteProperty { + val byteProperty: Byte = 42 +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithByteProperty() +var jsByteValue = kotlinClass.getByteProperty() // returns Kotlin Byte, converted to Number +``` + +- Kotlin's short type [kotlin.Short](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-short/index.html): + +```kotlin +package com.example + +class KotlinClassWithShortProperty { + val shortProperty: Short = 42 +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithShortProperty() +var jsShortValue = kotlinClass.getShortProperty() +``` +`getShortProperty()` - returns `Kotlin Short`, converted to `Number` + +- Kotlin's integer type [kotlin.Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html): + +```kotlin +package com.example + +class KotlinClassWithIntProperty { + val intProperty: Int = 42 +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithIntProperty() +var jsIntValue = kotlinClass.getIntProperty() +``` +`getIntProperty()` - returns `Kotlin Int`, converted to `Number` + +- Kotlin's float type [kotlin.Float](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float/index.html): + +```kotlin +package com.example + +class KotlinClassWithFloatProperty { + val floatProperty: Float = 42.0f +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithFloatProperty() +``` +`getFloatProperty()` - returns `Kotlin Float`, converted to `Number` + +- Kotlin's double type [kotlin.Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html): + +```kotlin +package com.example + +class KotlinClassWithDoubleProperty { + val doubleProperty: Double = 42.0 +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithDoubleProperty() +var jsDoubleValue = kotlinClass.getDoubleProperty() +``` +`getDoubleProperty()` - returns `Kotlin double`, converted to `Number` + +- Kotlin's long type [kotlin.Long](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long/index.html) is a special type which is projected to JavaScript by applying the following rules: + + - If the value is in the interval `(-2^53, 2^53)` then it is converted to [Number](http://www.w3schools.com/jsref/jsref_obj_number.asp) + - Else a special object with the following characteristics is created: + - Has Number.NaN set as a prototype + - Has value property set to the string representation of the Kotlin long value + - Its valueOf() method returns NaN + - Its toString() method returns the string representation of the Kotlin long value + +```kotlin +package com.example + +class KotlinClassWithLongProperties { + val longNumber54Bits: Long + get() = (1 shl 54).toLong() + val longNumber53Bits: Long + get() = (1 shl 53).toLong() +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithLongProperties() +var jsNumber = kotlinClass.getLongNumber53Bits() +var specialObject = kotlinClass.getLongNumber54Bits() +``` +`jsNumber` is a JavaScript Number and `specialObject` is the special object discussed above. + +## Converting Undefined & Null + +JavaScript [Undefined](http://www.w3schools.com/jsref/jsref_undefined.asp) & [Null](https://www.w3schools.com/js/js_type_conversion.asp) maps to Java and Kotlin [null literal](http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.7) (or null pointer). + +```js +var context = ...; +var button = new android.widget.Button(context); +button.setOnClickListener(undefined); +``` +In the abve example, the Java call will be made using the `null` keyword. + +## Array conversion + +A JavaScript [Array](http://www.w3schools.com/jsref/jsref_obj_array.asp) is implicitly converted to a [Java Array](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html) or a [Kotlin Array](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/index.html), using the above described rules for type conversion of the array's elements. For example: + +```js +var items = ['One', 'Two', 'Three'] +var myObject = new MyObject() +myObject.myMethod(items) +``` + +```java +class MyObject extends java.lang.Object { + public void myMethod(java.lang.String[] items){ + } +} +``` + +```kotlin +class MyObject : Any() { + fun myMethod(items: Array) {} +} +``` + +### Converting from Java/Kotlin arrays to JavaScript array +Array in Java/Kotlin is a special [java.lang.Object](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html) that have an implicit Class associated. A Java/Kotlin Array is projected to JavaScript as a special JavaScript proxy object with the following characteristics: + +- Has length property +- Has registered indexed getter and setter callbacks, which: + - If the array contains elements of type convertible to a JavaScript type, then accessing the i-th element will return a converted type + - If the array contains elements of type non-convertible to JavaScript, then accessing the i-th element will return a proxy object over the Java/Kotlin type see [Accessing APIs](#accessing-apis) + + + +```js +var directory = new java.io.File('path/to/myDir') +var files = directory.listFiles() // files is a special object as described above +var singleFile = files[0] // the indexed getter callback is triggered and a proxy object over the java.io.File is returned +``` + +```kotlin +package com.example + +class KotlinClassWithStringArrayProperty { + val stringArrayProperty: Array = arrayOf("element1", "element2", "element3") +} +``` + +```js +var kotlinClass = new com.example.KotlinClassWithStringArrayProperty() +var kotlinArray = kotlinClass.getStringArrayProperty() // kotlinArray is a special object as described above +var firstStringElement = kotlinArray[0] // the indexed getter callback is triggered and the kotlin.String is returned as a JS string +``` + +::: warning Note +A Java/Kotlin Array is intentionally not converted to a JavaScript [Array](http://www.w3schools.com/jsref/jsref_obj_array.asp) for the sake of performance, especially when it comes to large arrays. +::: + +##### Array of Objects + +Occasionally you have to create Java/Kotlin arrays from JavaScript. For this scenario we added method `create` to built-in JavaScript [`Array` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). Here are some examples how to use `Array.create` method: + +```js +// the following statement is equivalent to byte[] byteArr = new byte[10]; +var byteArr = Array.create('byte', 10) + +// the following statement is equivalent to String[] stringArr = new String[10]; +var stringArr = Array.create(java.lang.String, 10) +``` + +Here is the full specification for `Array.create` method + +```js +Array.create(elementClassName, length) +``` + +```js +Array.create(javaClassCtorFunction, length) +``` + +The first signature accepts `string` for `elementClassName`. This option is useful when you have to create Java array of primitive types (e.g. `char`, `boolean`, `byte`, `short`, `int`, `long`, `float` and `double`). It is also useful when you have to create Java jagged arrays. For this scenario `elementClassName` must be the standard JNI class notation. Here are some examples: + +```js +// equivalent to int[][] jaggedIntArray2 = new int[10][]; +var jaggedIntArray2 = Array.create('[I', 10) + +// equivalent to boolean[][][] jaggedBooleanArray3 = new boolean[10][][]; +var jaggedBooleanArray3 = Array.create('[[Z', 10) + +// equivalent to Object[][][][] jaggedObjectArray4 = new Object[10][][][]; +var jaggedObjectArray4 = Array.create('[[[Ljava.lang.Object;', 10) +``` + +The second signature uses `javaClassCtorFunction` which must the JavaScript constructor function for a given Java type. Here are some examples: + +```js +// equivalent to String[] stringArr = new String[10]; +var stringArr = Array.create(java.lang.String, 10) + +// equivalent to Object[] objectArr = new Object[10]; +var objectArr = Array.create(java.lang.Object, 10) +``` + +#### Array of Primitive Types + +The automatic marshalling works only for cases with arrays of objects. In cases where you have a method that takes an array of primitive types, you need to convert it as follows: + +```java +public static void myMethod(int[] someParam) +``` + +Then yoy need to invoke it as follows: + +```js +let arr = Array.create('int', 3) +arr[0] = 1 +arr[1] = 2 +arr[2] = 3 + +SomeObject.myMethod(arr) // assuming the method is accepting an array of primitive types +``` + +However there are some other helpful classes we can use to create a few other arrays of primitive types + +```js +const byteArray = java.nio.ByteBuffer.wrap([1]).array() +const shortArray = java.nio.ShortBuffer.wrap([1]).array() +const intArray = java.nio.IntBuffer.wrap([1]).array() +const longArray = java.nio.LongBuffer.wrap([1]).array() +const floatArray = java.nio.FloatBuffer.wrap([1]).array() +const doubleArray = java.nio.DoubleBuffer.wrap([1]).array() +``` + +##### Two-Dimensional Arrays of Primitive Types + +The above scenario gets more tricky with two-dimensional arrays. Consider a Java method that accepts as an argument a two-dimensional array: + +```java +public static void myMethod(java.lang.Integer[][] someParam) +``` + +The marshalled JavaScript code will look like this: + +```js +let arr = Array.create('[Ljava.lang.Integer;', 2) +let elements = Array.create('java.lang.Integer', 3) +elements[0] = new java.lang.Integer(1) +elements[1] = new java.lang.Integer(2) +elements[2] = new java.lang.Integer(3) +arr[0] = elements + +SomeObject.myMethod(arr) // assuming the method is accepting a two-dimensional array of primitive types +``` + + +```kotlin +interface Printer { + fun print(content: String) + fun print(content: String, offset: Int) +} + +interface Copier { + fun copy(content: String): String +} + +interface Writer { + fun write(arr: Array) + fun writeLine(arr: Array) +} +``` + +Implementing the interfaces: + +```java +public class MyVersatileCopywriter implements Printer, Copier, Writer { + public void print(String content) { ... } + + public void print(String content, int offset) { ... } + + public String copy(String content) { ... } + + public void write(Object[] arr) { ... } + + public void writeLine(Object[] arr) { ... } +} +``` + +```kotlin +class MyVersatileCopywriter: Printer, Copier, Writer{ + + override fun print(content: String) { ... } + + override fun print(content: String, offset: Int) { ... } + + override fun copy(content: String): String { ... } + + override fun write(arr: Array) { ... } + + override fun writeLine(arr: Array) { ... } +} +``` + +The same result can be achieved in NativeScript by extending any valid object that inherits [Java Object](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html). + +- In JavaScript - Declare an `interfaces` array in the implementation +- Using Typescript syntax - apply a `decorator` to the extended class (note `@Interfaces([...])`) + +Using Javascript syntax - attach `interfaces` array to implementation object of the extend call + +```js +let MyVersatileCopyWriter = java.lang.Object.extend({ + interfaces: [com.a.b.Printer, com.a.b.Copier, com.a.b.Writer], /* the interfaces that will be inherited by the resulting class */ + print: function() { ... }, /* implementing the 'print' methods from Printer */ + copy: function() { ... }, /* implementing the 'copy' method from Copier */ + write: function() { ... }, /* implementing the 'write' method from Writer */ + writeLine: function() { ... }, /* implementing the 'writeLine' method from Writer */ + toString: function() { ... } /* override `java.lang.Object's` `toString */ +}); +``` + +```ts +@Interfaces([com.a.b.Printer, com.a.b.Copier, com.a.b.Writer]) /* the interfaces that will be inherited by the resulting MyVersatileCopyWriter class */ +class MyVersatileCopyWriter extends java.lang.Object { + constructor() { + super(); + return global.__native(this); + } + + print() { ... } + copy() { ... } + write() { ... } + writeLine() { ... } +} +``` + +:::warning +- Implementing two interfaces with the same method signature will generate just 1 method. It is the implementor's responsibility to define how the method will behave for both interfaces + +- Implementing two interfaces with the same _method name_, _parameter number_, but **different return type** (`void a()` vs `boolean a()`) will result in a compilation error. +::: + +:::warning Note +Java/Kotlin method overloads are handled by the developer by explicitly checking the arguments count of the invoked function +::: + +```ts +class MyVersatileCopyWriter extends ... { + constructor() { + super(); + return global.__native(this); + } + ... + print() { + let content = ""; + let offset = 0; + + if (arguments.length == 2) { + offset = arguments[1]; + } + + content = arguments[0]; + + // do stuff + } + ... +} +``` +:::tip Note +In addition to implementing interface methods, you can override methods of the extended class, and also declare your own methods that the new class should have. +::: + +## Java nested types in NativeScript + +```java +public class Outer { + public class Inner { + // inner and nested class + } + + public static class Nested { + // nested but not inner class + } +} +``` +```java +//Instantiate nested types +Outer outer = new Outer(); +Outer.Inner inner1 = outer.new Inner(); + +Outer.Inner inner2 = new Outer().new Inner(); + +Outer.Nested nested = new Outer.Nested() +``` +```ts +var outer = new Outer(); + +var inner1 = new outer.Inner(); + +var inner2 = new new Outer().Inner(); + +var nested = new Outer.Nested(); + +```` +## Kotlin Types + +All Kotlin types are projected to JavaScript using the Package and Class proxies as described in + +## Kotlin Companion objects + +You can access Kotlin's [companion objects](https://khan.github.io/kotlin-for-python-developers/#objects-and-companion-objects#companion-objects) via the `Companion` field: + +```kotlin +package com.example + +class KotlinClassWithCompanion { + companion object { + fun getDataFromCompanion() = "some data" + } +} +``` + +```js +var companion = com.example.KotlinClassWithCompanion.Companion +var data = companion.getDataFromCompanion() +``` + +## Kotlin Object + +To access the Kotlin's [objects](https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html#object-declarations), use the `INSTANCE` field: + +```kotlin +package com.example + +object KotlinObject { + fun getDataFromObject() = "some data" +} +``` + +```js +var objectInstance = com.example.KotlinObject.INSTANCE +var data = objectInstance.getDataFromObject() +``` + +## Accessing Kotlin properties + +To access the Kotlin's [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields), use their compiler-generated get/set methods. Non-boolean Kotlin properties could be used in NativeScript applications as JS fields as well. + + +```kotlin +package com.example + +class KotlinClassWithStringProperty(var stringProperty: kotlin.String) +``` + +```js +var kotlinClass = new com.example.KotlinClassWithStringProperty() + +var propertyValue = kotlinClass.getStringPropert() +kotlinClass.setStringProperty('example') + +propertyValue = kotlinClass.stringProperty +kotlinClass.stringProperty = 'second example' +``` + +## Accessing Kotlin package-level functions + +In order to use a Kotlin [package-level function](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#package-level-functions), the class where it's defined should be known. Let's take a look at an example: + +```kotlin +package com.example + +fun getRandomNumber() = 42 +``` + +```js +var randomNumber = com.example.FunctionsKt.getRandomNumber() +``` + +In the example above, the class `FunctionsKt` is autogenerated by the Kotlin compiler and its name is based on the name of the file where the functions are defined. Kotlin supports annotating a file to have a user provided name and this simplifies using package-level functions: + +```js +var randomNumber = com.example.UtilityFunctions.getRandomNumber() +``` + +```kotlin +@file:JvmName("UtilityFunctions") +package com.example + +fun getRandomNumber() = 42 +``` + +## Accessing Kotlin extension functions + + In order to use an extension function, the class where it's defined should be known. Also, when invoking it, the first parameter should be an instance of the type for which the function is defined. Let's take a look at an example: + +```kotlin +package com.example + +import java.util.ArrayList + +fun ArrayList.switchPlaces(firstElementIndex: Int, secondElementIndex: Int) { + val temp = this[firstElementIndex] + this[firstElementIndex] = this[secondElementIndex] + this[secondElementIndex] = temp +} +``` +```js +var arrayList = new java.util.ArrayList() +arrayList.add('firstElement') +arrayList.add('secondElement') +com.example.Extensions.switchPlaces(arrayList, 0, 1) +``` + +In the example above, the class `ExtensionsKt` is autogenerated by the Kotlin compiler and its name is based on the name of the file where the functions are defined. Kotlin supports annotating a file to have a user provided name and this simplifies using package-level functions: + +```kotlin +@file:JvmName("ExtensionFunctions") +package com.example + +import java.util.ArrayList + +fun ArrayList.switchPlaces(firstElementIndex: Int, secondElementIndex: Int) { + val temp = this[firstElementIndex] + this[firstElementIndex] = this[secondElementIndex] + this[secondElementIndex] = temp +} +``` + +```js +var arrayList = new java.util.ArrayList() +arrayList.add('firstElement') +arrayList.add('secondElement') +com.example.ExtensionFunctions.switchPlaces(arrayList, 0, 1) +``` + diff --git a/content/sidebar.ts b/content/sidebar.ts index c95688b9..fa7975f8 100644 --- a/content/sidebar.ts +++ b/content/sidebar.ts @@ -107,6 +107,15 @@ export default [ text: 'Code Sharing', link: '/guide/code-sharing', }, + { + text: 'Marshalling', + items: [ + { + text: 'Android Marshalling', + link: '/guide/marshalling/nativescript-android-marshalling', + }, + ], + } ], }, // { From c9c92023063438e8e9c6598289f14da7d8b16a62 Mon Sep 17 00:00:00 2001 From: Ombuweb Date: Mon, 21 Nov 2022 18:36:00 +0100 Subject: [PATCH 02/14] fix: shortened link --- ...tivescript-android-marshalling.md => android-marshalling.md} | 0 content/sidebar.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename content/guide/{marshalling/nativescript-android-marshalling.md => android-marshalling.md} (100%) diff --git a/content/guide/marshalling/nativescript-android-marshalling.md b/content/guide/android-marshalling.md similarity index 100% rename from content/guide/marshalling/nativescript-android-marshalling.md rename to content/guide/android-marshalling.md diff --git a/content/sidebar.ts b/content/sidebar.ts index fa7975f8..ae8ff18a 100644 --- a/content/sidebar.ts +++ b/content/sidebar.ts @@ -112,7 +112,7 @@ export default [ items: [ { text: 'Android Marshalling', - link: '/guide/marshalling/nativescript-android-marshalling', + link: '/guide/android-marshalling', }, ], } From e842ebae82abf60a8d14c651518ed13b61a3b173 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:45:46 -0700 Subject: [PATCH 03/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 6253a067..d38e1b4e 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -2,7 +2,7 @@ title: Android Marshalling --- -This article looks at how NativeScript handles the conversion between JavaScript data types and Java/Kotlin data types. +NativeScript seamlessly handles data type conversion between JavaScript and Java/Kotlin, utilizing type inference and dedicated wrappers, ensuring smooth integration and type safety in cross-platform development. ## String Conversion ### Converting JavaScript String to Java string types From bbab7e7c273b9e4d8577fb4c4b8c31388ba9481b Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:46:29 -0700 Subject: [PATCH 04/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index d38e1b4e..5a73e209 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -186,7 +186,7 @@ myObject.myMethod(10.5) // myMethod(Double) will be called. The JavaScript `10.5` `Number` gets converted to Java/Kotlin `double` and then myMethod(ouble) gets called. ::: warning Note -If there is no myMethod(double) implementation, the Runtime will try to choose the best possible overload with least conversion loss. If no such method is found an exception will be raised. +In a scenario where no myMethod(double) implementation exists, the Runtime will attempt to select the most suitable possible overload, with the least amount of conversion loss. If no such method is found an exception thrown. ::: #### Explicit conversion From 06d341b0756fbb21d57a2fae23b001a2ead8daf9 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:47:15 -0700 Subject: [PATCH 05/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 5a73e209..c8bd7223 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -492,7 +492,7 @@ var objectArr = Array.create(java.lang.Object, 10) #### Array of Primitive Types -The automatic marshalling works only for cases with arrays of objects. In cases where you have a method that takes an array of primitive types, you need to convert it as follows: +When dealing with arrays of primitive types, automatic marshalling is not supported. To pass them as arguments to a method, you'll need to use wrapper classes (e.g., Integer, Double) to convert the primitives into objects, allowing for automatic marshalling. ```java public static void myMethod(int[] someParam) From 0215220bab33fdcfaf28b72a0005fb4f074fdc23 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:47:40 -0700 Subject: [PATCH 06/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index c8bd7223..1a74f161 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -480,7 +480,7 @@ var jaggedBooleanArray3 = Array.create('[[Z', 10) var jaggedObjectArray4 = Array.create('[[[Ljava.lang.Object;', 10) ``` -The second signature uses `javaClassCtorFunction` which must the JavaScript constructor function for a given Java type. Here are some examples: +The second signature requires you to provide the `javaClassCtorFunction`, which must be the JavaScript constructor function representing the desired Java type. Here are some examples: ```js // equivalent to String[] stringArr = new String[10]; From 2e5a51713c792ad6ba4f0166826c771367634223 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:48:13 -0700 Subject: [PATCH 07/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 1a74f161..ccbe9205 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -467,7 +467,7 @@ Array.create(elementClassName, length) Array.create(javaClassCtorFunction, length) ``` -The first signature accepts `string` for `elementClassName`. This option is useful when you have to create Java array of primitive types (e.g. `char`, `boolean`, `byte`, `short`, `int`, `long`, `float` and `double`). It is also useful when you have to create Java jagged arrays. For this scenario `elementClassName` must be the standard JNI class notation. Here are some examples: +The first signature accepts a `string` type for an `elementClassName`. This option becomes beneficial when the creation of a Java array of primitive types (e.g. `char`, `boolean`, `byte`, `short`, `int`, `long`, `float` and `double`) is required. This also applicable when the creation of Java jagged arrays is needed. For this scenario `elementClassName` must be the standard JNI class notation. Here are some examples: ```js // equivalent to int[][] jaggedIntArray2 = new int[10][]; From ba6a86af945cd91f28fcaf47b5571baff3a0cce5 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:49:03 -0700 Subject: [PATCH 08/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index ccbe9205..6ceaf145 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -447,7 +447,7 @@ A Java/Kotlin Array is intentionally not converted to a JavaScript [Array](http: ##### Array of Objects -Occasionally you have to create Java/Kotlin arrays from JavaScript. For this scenario we added method `create` to built-in JavaScript [`Array` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). Here are some examples how to use `Array.create` method: +In scenarios where the creation of Java/Kotlin arrays from JavaScript is mandatory. In the given scenario, we have extended the built-in JavaScript Array object by adding a custom method named create. By doing so, we have augmented the default functionality of the Array object with our own implementation to cater to specific requirements in built-in JavaScript [`Array` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). Here are some examples how to use `Array.create` method: ```js // the following statement is equivalent to byte[] byteArr = new byte[10]; From d5d9b43a9650da2fd1a5b2bd2cdacc09f871ada1 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:51:51 -0700 Subject: [PATCH 09/14] Update content/guide/android-marshalling.md --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 6ceaf145..0dbc147b 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -22,7 +22,7 @@ button.setText(text); JavaScript [String](http://www.w3schools.com/jsref/jsref_obj_string.asp) maps to [kotlin.String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html): ```js -var kotlinClass = new com.example.KotlinClassWithStringProperty() +const kotlinClass = new com.example.KotlinClassWithStringProperty() var text = 'My Button' kotlinClass.setStringProperty(text) / ``` From 864c13149daeed411185cfae793806d64b5b45a4 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:52:26 -0700 Subject: [PATCH 10/14] Update content/guide/android-marshalling.md --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 0dbc147b..16f2edab 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -115,7 +115,7 @@ var enabled = kotlinClass.getBooleanProperty() // returns Kotlin Boolean, conver ### Converting JavaScript Number to Java/Kotlin numeric types -Java and Koltin have several primitive numeric types while JavaScript has the `Number` type only. Additionally, unlike JavaScript, Java and Kotlin support [Method Overloading](http://en.wikipedia.org/wiki/Function_overloading), which makes the numeric conversion more complex. +Java and Kotlin have several primitive numeric types while JavaScript has the `Number` type only. Additionally, unlike JavaScript, Java and Kotlin support [Method Overloading](http://en.wikipedia.org/wiki/Function_overloading), which makes the numeric conversion more complex. Consider the following examples: From 42a489291293de3f5575a9989d486882ac3542a1 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:53:31 -0700 Subject: [PATCH 11/14] Update content/guide/android-marshalling.md --- content/guide/android-marshalling.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 16f2edab..e0bc1a76 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -588,7 +588,6 @@ class MyVersatileCopywriter: Printer, Copier, Writer{ override fun writeLine(arr: Array) { ... } } ``` - The same result can be achieved in NativeScript by extending any valid object that inherits [Java Object](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html). - In JavaScript - Declare an `interfaces` array in the implementation From ce7c7636f2d45af304ffe9fe45f73977d81b6a8a Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:54:13 -0700 Subject: [PATCH 12/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index e0bc1a76..01cca309 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -654,7 +654,7 @@ class MyVersatileCopyWriter extends ... { } ``` :::tip Note -In addition to implementing interface methods, you can override methods of the extended class, and also declare your own methods that the new class should have. +In OOP, when a class extends another class aka inheritance, the new class not only gains access to the interface methods it must implement, but also has the ability to override methods from the extended class. Moreover, it can introduce new methods specific to the new class's functionality. This enables the new class to extend and enhance the behaviour of its parent class while providing additional functionality of its own. ::: ## Java nested types in NativeScript From e57425ec54d3136e249399cd0daffa5a66b7fae3 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:55:20 -0700 Subject: [PATCH 13/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 01cca309..711f62ec 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -779,7 +779,7 @@ fun getRandomNumber() = 42 ## Accessing Kotlin extension functions - In order to use an extension function, the class where it's defined should be known. Also, when invoking it, the first parameter should be an instance of the type for which the function is defined. Let's take a look at an example: +In order to use an extension function, the class where it's defined is required to be known. Also, when invoking this function, the first parameter should be an instance of the type for which the function is defined. Let's take a look at an example: ```kotlin package com.example From a5201127b3db8975ac32ba3a44f20c1eed6a2137 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sat, 29 Jul 2023 13:56:08 -0700 Subject: [PATCH 14/14] Update content/guide/android-marshalling.md Co-authored-by: Sean Kelly <36159246+SeanKelly369@users.noreply.github.com> --- content/guide/android-marshalling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/guide/android-marshalling.md b/content/guide/android-marshalling.md index 711f62ec..de51fe62 100644 --- a/content/guide/android-marshalling.md +++ b/content/guide/android-marshalling.md @@ -799,7 +799,7 @@ arrayList.add('secondElement') com.example.Extensions.switchPlaces(arrayList, 0, 1) ``` -In the example above, the class `ExtensionsKt` is autogenerated by the Kotlin compiler and its name is based on the name of the file where the functions are defined. Kotlin supports annotating a file to have a user provided name and this simplifies using package-level functions: +In the example above, the class `ExtensionsKt` is autogenerated by the Kotlin compiler and its name is derived on the name of the file where the functions are defined. Kotlin supports annotating a file to have a user provided name, simplifying using package-level functions: ```kotlin @file:JvmName("ExtensionFunctions")