Skip to content

This is Objective-C code wrapper generator over the java library (.jar) using JNI calls

License

Notifications You must be signed in to change notification settings

ashitikov/Objective-JNI

Repository files navigation

Objective-JNI

This is Objective-C code wrapper generator over the java library (.jar) using JNI calls. Environment is available here: https://github.com/ashitikov/Objective-JNI-Environment

Usage:

java -jar Objective-JNI-1.0-SNAPSHOT.jar

Options:

 -class,--class <arg>                     Specify java class to generate
                                          Objective-C wrapper
 -classpath,--classpath <arg>             Specify .jar classpath file to
                                          generate Objective-C wrapper.
 -exclude,--exclude <arg>                 Explicitely exclude java class.
                                          Objective-C wrapper will not be
                                          generated for that.
 -excludepackage,--excludepackage <arg>   Explicitly excludes java
                                          package. Objective-C wrapper
                                          will not be generated for all
                                          types inside this package.
 -help,--help                             Print this message
 -output,--output <arg>                   Specify output dir to put all
                                          generated wrappers to.
 -package,--package <arg>                 Specify java package to generate
                                          Objective-C wrappers for classes
                                          inside.
 -prefix,--prefix <arg>                   Specify class name prefix for
                                          each generated Objective-C
                                          wrapper.
 -version,--version                       Print Objective-JNI version

Example:

java -jar Objective-JNI-1.0-SNAPSHOT.jar --output ./generated --prefix AS --classpath ./some-java-code.jar --class java.lang.Integer

It's recommended to use OpenJDK 1.7.

Wrapper generation

Each java class from classpath (--classpath option) or concrete one that you specified explicitly in --class option will be generated Objective-C wrapper, except private classes. Classes and interface inheritance will be saved. Type convertion:

Java Objective-C
Class @interface
Interface @protocol
int int
long long
short short
byte char
boolean bool
float float
double double
void void

Property generation

To avoid overload problems and name conflicts, all properties will be generated with prefix property_. In case of final property, setter will not be generated. Example. Java property:

public String testString;

Generated Objective-C getter and setter:

- (String *)property_testString;
- (void)setProperty_testString:(String *)value;

Private properties will be ignored. You can use @OJNIExportName annotation to change name and @OJNIExclude to exclude it from wrapper.

Method generation

Example. Java methods:

public String getTestString() { 
   return testString;
}

public void setTestString(String value) {
   testString = value;
}

Generated Objective-C wrapper:

- (String *)getTestString;
- (void)setTestString:(String *)value;

Please, note, that *(String ) is not the same as *(NSString ). In that context, *(String ) is Objective-C wrapper for java class String. For more comfort, there is a special helper methods right for String:

- (instancetype)initWithNSString:(NSString *)string;
+ (instancetype)stringWithNSString:(NSString *)string;
- (NSString *)toNSString;

So you can easily create java string right from Objective-C code:

SomeClass *javaClass = [[SomeClass alloc] init]; // call empty constructor
String *str = [String stringWithNSString:@"Hello, World!"];
[javaClass setTestString:str];

Or easily convert it back:

NSString *nsstr = [[javaClass getTestString] toNSString];
NSLog(@"Got test string from java: %@", nsstr);

There is a big problem: Objective-C doesn't support method overloading. Thats why this java code:

public void overload(int a) {}
public void overload(int a, int b) {}
public void overload(String str) {}

will be translated to Objective-C wrapper:

- (void)overloadWithAint:(int)a ;
- (void)overload:(int)a b:(int)b ;
- (void)overloadWithStrString:(ASString *)str ;
Constructors

Example. Java class:

public class SomeClass {
   // with overloading
   public SomeClass() { }
   public SomeClass(int a) { }
   public SomeClass(String a) { }
}

Objective-C translated:

@interface SomeClass : Object
- (instancetype)init;
- (instancetype)initWithaInt:(int)a;
- (instancetype)initWithaString:(String *)a;
@end

Private methods will be ignored. You can use @OJNIExportName annotation to change name and @OJNIExclude to exclude it from wrapper.

Arrays

There is two types of arrays:

  1. Primitive (int[], float[] ...)
  2. Object (String[], Object[] ...)

Primitive array

All primitive arrays like int[], float[] and etc. translates to OJNIPrimitive##Type##Array, where ##Type## is Int, Float and etc. Java example:

public int[] getGivenArray(int[] array) {
   return array;
}

Translated Objective-C:

- (OJNIPrimitiveIntArray *)getGivenArray(OJNIPrimitiveIntArray *)array;

OJNIPrimitiveArray classes uses standard C arrays, right like NSData * class.

Multidimensional example:

public int[][] getGivenArray(int[][] array) {
   return array;
}

Translated:

- (NSArray <OJNIPrimitiveIntArray *> *)getGivenArray(NSArray <OJNIPrimitiveIntArray *> *)array;

For the comfort, there is a helper methods to create OJNIPrimitiveArray without C arrays like:

- (instancetype)initWithNumberArray:(NSArray <NSNumber *> *)numberArray;
+ (instancetype)arrayWithNumberArray:(NSArray <NSNumber *> *)numberArray;

//using
OJNIPrimitiveIntArray * array = [OJNIPrimitiveIntArray arrayWithNumberArray:@[@(1), @(2), @(3)]];
NSArray <OJNIPrimitiveIntArray *> *result = [SomeClass getGivenArray:@[array]];
for (int i = 0; i < result.count; i++) {
   int stored = [result[i] intAtIndex:i];
   // do smth with stored.
}

Object array

All object arrays like String[], Object[] and etc. translates to NSArray <##ObjectType##> *, where ##ObjectType## is object class. Java example:

public String[] getGivenArray(String[] array) {
   return array;
}

Translated Objective-C:

- (NSArray <String *> *)getGivenArray(NSArray <String *> *)array;

Multidimensional example:

public String[][] getGivenArray(String[][] array) {
   return array;
}

Translated:

- (NSArray <NSArray <String *> *> *)getGivenArray(NSArray <NSArray <String *> *> *)array;

Exceptions

There is 2 types of exceptions:

  1. Environment exception (OJNIEnvironmentException *)
  2. Java exception (OJNIJavaException *)

Environment exception occures when input or output data cannot be handles properly. For example if you are trying to pass invalid object, or method/field not found in java class.

Java exception occures when java method throws it. You can catch it as usual objective-c way: Java example:

public String[] getGivenArray(String[] array) throws NullPointerException {
   throw new NullPointerException("Test exception");
   return array;
}

Translated Objective-C:

- (NSArray <String *> *)getGivenArray(NSArray <String *> *)array;

// using 
@try {
   [SomeClass getGivenArray:@[[String stringWithNSString:@"Test"]];
} @catch (OJNIJavaException *je) {
   NSLog(@"Got a java exception %@", je);
} @catch (OJNIEnvironmentException *ee) {
   NSLog(@"Got an environment exception %@", ee);
} @finally {
   NSLog(@"Finally");
}

Memory Management

While Objective-C wrapper object is live, java object is also live. So there is two cases that we need to review:

  1. Object created by calling a constructor. In such case, JNI creates new global reference, and hold it until dealloc() in Objective-C wrapper not called.
  2. Object returned from method. If found the same already created Objective-C wrapper object, then nothing happens, else one creates.

NOTICE: Be careful using java singletones. Because of wrapper does not contain any information about static objects, each time you'll call [SomeClass instance] you will get new wrapper object, until you will not store the reference to it, although java object will be the same.

Objective-JNI-Annotations

You can find more here: https://github.com/ashitikov/Objective-JNI/tree/master/Objective-JNI-Annotations