- add sources.
[platform/framework/web/crosswalk.git] / src / base / android / jni_generator / java / src / org / chromium / example / jni_generator / SampleForTests.java
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.example.jni_generator;
6
7 import android.graphics.Rect;
8
9 import java.util.ArrayList;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13
14 import org.chromium.base.AccessedByNative;
15 import org.chromium.base.CalledByNative;
16 import org.chromium.base.CalledByNativeUnchecked;
17 import org.chromium.base.JNINamespace;
18 import org.chromium.base.NativeClassQualifiedName;
19
20
21 // This class serves as a reference test for the bindings generator, and as example documentation
22 // for how to use the jni generator.
23 // The C++ counter-part is sample_for_tests.cc.
24 // jni_generator.gyp has a jni_generator_tests target that will:
25 //   * Generate a header file for the JNI bindings based on this file.
26 //   * Compile sample_for_tests.cc using the generated header file.
27 //   * link a native executable to prove the generated header + cc file are self-contained.
28 // All comments are informational only, and are ignored by the jni generator.
29 //
30 // Binding C/C++ with Java is not trivial, specially when ownership and object lifetime
31 // semantics needs to be managed across boundaries.
32 // Following a few guidelines will make the code simpler and less buggy:
33 //
34 // - Never write any JNI "by hand". Rely on the bindings generator to have a thin
35 // layer of type-safety.
36 //
37 // - Treat the types from the other side as "opaque" as possible. Do not inspect any
38 // object directly, but rather, rely on well-defined getters / setters.
39 //
40 // - Minimize the surface API between the two sides, and rather than calling multiple
41 // functions across boundaries, call only one (and then, internally in the other side,
42 // call as many little functions as required).
43 //
44 // - If a Java object "owns" a native object, stash the pointer in a "int mNativeClassName".
45 // Note that it needs to have a "destruction path", i.e., it must eventually call a method
46 // to delete the native object (for example, the java object has a "close()" method that
47 // in turn deletes the native object). Avoid relying on finalizers: those run in a different
48 // thread and makes the native lifetime management more difficult.
49 //
50 // - For native object "owning" java objects:
51 //   - If there's a strong 1:1 to relationship between native and java, the best way is to
52 //   stash the java object into a base::android::ScopedJavaGlobalRef. This will ensure the
53 //   java object can be GC'd once the native object is destroyed but note that this global strong
54 //   ref implies a new GC root, so be sure it will not leak and it must never rely on being
55 //   triggered (transitively) from a java side GC.
56 //   - In all other cases, the native side should keep a JavaObjectWeakGlobalRef, and check whether
57 //   that reference is still valid before de-referencing it. Note that you will need another
58 //   java-side object to be holding a strong reference to this java object while it is in use, to
59 //   avoid unpredictable GC of the object before native side has finished with it.
60 //
61 // - The best way to pass "compound" datatypes across in either direction is to create an inner
62 // class with PODs and a factory function. If possible, make it immutable (i.e., mark all the
63 // fields as "final"). See examples with "InnerStructB" below.
64 //
65 // - It's simpler to create thin wrappers with a well defined JNI interface than to
66 // expose a lot of internal details. This is specially significant for system classes where it's
67 // simpler to wrap factory methods and a few getters / setters than expose the entire class.
68 //
69 // - Use static factory functions annotated with @CalledByNative rather than calling the
70 // constructors directly.
71 //
72 // - Iterate over containers where they are originally owned, then create inner structs or
73 // directly call methods on the other side. It's much simpler than trying to amalgamate
74 // java and stl containers.
75 //
76 // This JNINamespace annotation indicates that all native methods should be
77 // generated inside this namespace, including the native class that this
78 // object binds to.
79 @JNINamespace("base::android")
80 class SampleForTests {
81   // Classes can store their C++ pointer counter part as an int that is normally initialized by
82   // calling out a nativeInit() function.
83   int mNativeCPPObject;
84
85   // You can define methods and attributes on the java class just like any other.
86   // Methods without the @CalledByNative annotation won't be exposed to JNI.
87   public SampleForTests() {
88   }
89
90   public void startExample() {
91       // Calls native code and holds a pointer to the C++ class.
92       mNativeCPPObject = nativeInit("myParam");
93   }
94
95   public void doStuff() {
96       // This will call CPPClass::Method() using nativePtr as a pointer to the object. This must be
97       // done to:
98       // * avoid leaks.
99       // * using finalizers are not allowed to destroy the cpp class.
100       nativeMethod(mNativeCPPObject);
101   }
102
103   public void finishExample() {
104       // We're done, so let's destroy nativePtr object.
105       nativeDestroy(mNativeCPPObject);
106   }
107
108   // -----------------------------------------------------------------------------------------------
109   // The following methods demonstrate exporting Java methods for invocation from C++ code.
110   // Java functions are mapping into C global functions by prefixing the method name with
111   // "Java_<Class>_"
112   // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
113
114   // Exported to C++ as:
115   //   Java_Example_javaMethod(JNIEnv* env, jobject obj, jint foo, jint bar)
116   // Typically the C++ code would have obtained the jobject via the Init() call described above.
117   @CalledByNative
118   public int javaMethod(int foo,
119                         int bar) {
120       return 0;
121   }
122
123   // Exported to C++ as Java_Example_staticJavaMethod(JNIEnv* env)
124   // Note no jobject argument, as it is static.
125   @CalledByNative
126   public static boolean staticJavaMethod() {
127       return true;
128   }
129
130   // No prefix, so this method is package private. It will still be exported.
131   @CalledByNative
132   void packagePrivateJavaMethod() {}
133
134   // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that
135   // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to
136   // call ClearException() and act as appropriate.
137   // See more details at the "@CalledByNativeUnchecked" annotation.
138   @CalledByNativeUnchecked
139   void methodThatThrowsException() throws Exception {}
140
141   // The generator is not confused by inline comments:
142   // @CalledByNative void thisShouldNotAppearInTheOutput();
143   // @CalledByNativeUnchecked public static void neitherShouldThis(int foo);
144
145   /**
146    * The generator is not confused by block comments:
147    * @CalledByNative void thisShouldNotAppearInTheOutputEither();
148    * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo);
149    */
150
151   // String constants that look like comments don't confuse the generator:
152   private String arrgh = "*/*";
153
154   //------------------------------------------------------------------------------------------------
155   // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
156   // prevent them being eliminated when unreferenced code is stripped.
157   @AccessedByNative
158   private int javaField;
159
160   //------------------------------------------------------------------------------------------------
161   // The following methods demonstrate declaring methods to call into C++ from Java.
162   // The generator detects the "native" and "static" keywords, the type and name of the first
163   // parameter, and the "native" prefix to the function name to determine the C++ function
164   // signatures. Besides these constraints the methods can be freely named.
165
166   // This declares a C++ function which the application code must implement:
167   //   static jint Init(JNIEnv* env, jobject obj);
168   // The jobject parameter refers back to this java side object instance.
169   // The implementation must return the pointer to the C++ object cast to jint.
170   // The caller of this method should store it, and supply it as a the nativeCPPClass param to
171   // subsequent native method calls (see the methods below that take an "int native..." as first
172   // param).
173   private native int nativeInit(String param);
174
175   // This defines a function binding to the associated C++ class member function. The name is
176   // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e. native
177   // prefixes stripped).
178   // The |nativeCPPClass| is automatically cast to type CPPClass* in order to obtain the object on
179   // which to invoke the member function.
180   private native void nativeDestroy(int nativeCPPClass);
181
182   // This declares a C++ function which the application code must implement:
183   //   static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
184   // The jobject parameter refers back to this java side object instance.
185   private native double nativeGetDoubleFunction();
186
187   // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather than
188   // jobject param, as the function is declared static.
189   private static native float nativeGetFloatFunction();
190
191   // This function takes a non-POD datatype. We have a list mapping them to their full classpath in
192   // jni_generator.py JavaParamToJni. If you require a new datatype, make sure you add to that
193   // function.
194   private native void nativeSetNonPODDatatype(Rect rect);
195
196   // This declares a C++ function which the application code must implement:
197   //   static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject obj);
198   // The jobject parameter refers back to this java side object instance.
199   // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
200   // deleting the JNI local reference.  This is similar with Strings and arrays.
201   private native Object nativeGetNonPODDatatype();
202
203   // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass type and
204   // call its Method member function.
205   private native int nativeMethod(int nativeCPPClass);
206
207   // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the
208   // annotation rather than parameter name, which can thus be chosen freely.
209   @NativeClassQualifiedName("CPPClass::InnerClass")
210   private native double nativeMethodOtherP0(int nativePtr);
211
212   // This "struct" will be created by the native side using |createInnerStructA|,
213   // and used by the java-side somehow.
214   // Note that |@CalledByNative| has to contain the inner class name.
215   static class InnerStructA {
216       private final long mLong;
217       private final int mInt;
218       private final String mString;
219
220       private InnerStructA(long l, int i, String s) {
221           mLong = l;
222           mInt = i;
223           mString = s;
224       }
225
226       @CalledByNative("InnerStructA")
227       private static InnerStructA create(long l, int i, String s) {
228           return new InnerStructA(l, i, s);
229       }
230   }
231
232   private List<InnerStructA> mListInnerStructA = new ArrayList<InnerStructA>();
233
234   @CalledByNative
235   private void addStructA(InnerStructA a) {
236       // Called by the native side to append another element.
237       mListInnerStructA.add(a);
238   }
239
240   @CalledByNative
241   private void iterateAndDoSomething() {
242       Iterator<InnerStructA> it = mListInnerStructA.iterator();
243       while (it.hasNext()) {
244           InnerStructA element = it.next();
245           // Now, do something with element.
246       }
247       // Done, clear the list.
248       mListInnerStructA.clear();
249   }
250
251   // This "struct" will be created by the java side passed to native, which
252   // will use its getters.
253   // Note that |@CalledByNative| has to contain the inner class name.
254   static class InnerStructB {
255       private final long mKey;
256       private final String mValue;
257
258       private InnerStructB(long k, String v) {
259           mKey = k;
260           mValue = v;
261       }
262
263       @CalledByNative("InnerStructB")
264       private long getKey() {
265           return mKey;
266       }
267
268       @CalledByNative("InnerStructB")
269       private String getValue() {
270           return mValue;
271       }
272   }
273
274   List<InnerStructB> mListInnerStructB = new ArrayList<InnerStructB>();
275
276   void iterateAndDoSomethingWithMap() {
277       Iterator<InnerStructB> it = mListInnerStructB.iterator();
278       while (it.hasNext()) {
279           InnerStructB element = it.next();
280           // Now, do something with element.
281           nativeAddStructB(mNativeCPPObject, element);
282       }
283       nativeIterateAndDoSomethingWithStructB(mNativeCPPObject);
284   }
285
286   native void nativeAddStructB(int nativeCPPClass, InnerStructB b);
287   native void nativeIterateAndDoSomethingWithStructB(int nativeCPPClass);
288 }