diff --git a/jni/native/linux_x86_64/libnative.so b/jni/native/linux_x86_64/libnative.so
new file mode 100755
index 0000000000..213491e268
Binary files /dev/null and b/jni/native/linux_x86_64/libnative.so differ
diff --git a/jni/native/macos/libnative.dylib b/jni/native/macos/libnative.dylib
new file mode 100755
index 0000000000..6d1264d696
Binary files /dev/null and b/jni/native/macos/libnative.dylib differ
diff --git a/jni/native/win32/native.dll b/jni/native/win32/native.dll
new file mode 100644
index 0000000000..683cdb1435
Binary files /dev/null and b/jni/native/win32/native.dll differ
diff --git a/jni/pom.xml b/jni/pom.xml
new file mode 100644
index 0000000000..752277f526
--- /dev/null
+++ b/jni/pom.xml
@@ -0,0 +1,15 @@
+
+ 4.0.0
+ com.baeldung
+ jni
+ 0.0.1-SNAPSHOT
+
+
+
+ junit
+ junit
+ 4.8.1
+ test
+
+
+
\ No newline at end of file
diff --git a/jni/src/main/cpp/com_baeldung_jni_ExampleObjectsJNI.cpp b/jni/src/main/cpp/com_baeldung_jni_ExampleObjectsJNI.cpp
new file mode 100644
index 0000000000..65c11cb9e1
--- /dev/null
+++ b/jni/src/main/cpp/com_baeldung_jni_ExampleObjectsJNI.cpp
@@ -0,0 +1,48 @@
+#include "com_baeldung_jni_ExampleObjectsJNI.h"
+#include
+
+/*
+ * Class: com_baeldung_jni_ExampleObjectsJNI
+ * Method: createUser
+ * Signature: (Ljava/lang/String;D)Lcom/baeldung/jni/UserData;
+ */
+JNIEXPORT jobject JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_createUser
+ (JNIEnv *env, jobject thisObject, jstring name, jdouble balance){
+
+ // Create the object of the class UserData
+ jclass userDataClass = env->FindClass("com/baeldung/jni/UserData");
+ jobject newUserData = env->AllocObject(userDataClass);
+
+ // Get UserData fields to set
+ jfieldID nameField = env->GetFieldID(userDataClass , "name", "Ljava/lang/String;");
+ jfieldID balanceField = env->GetFieldID(userDataClass , "balance", "D");
+
+ // Set the values of the new object
+ env->SetObjectField(newUserData, nameField, name);
+ env->SetDoubleField(newUserData, balanceField, balance);
+
+ // Return the created object
+ return newUserData;
+ }
+
+/*
+ * Class: com_baeldung_jni_ExampleObjectsJNI
+ * Method: printUserData
+ * Signature: (Lcom/baeldung/jni/UserData;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_printUserData
+ (JNIEnv *env, jobject thisObject, jobject userData){
+
+ // Find the class method id
+ jclass userDataClass = env->GetObjectClass(userData);
+ jmethodID methodId = env->GetMethodID(userDataClass, "getUserInfo", "()Ljava/lang/String;");
+
+ // Call the object method and get the result
+ jstring result = (jstring)env->CallObjectMethod(userData, methodId);
+
+ // Print the result
+ std::cout << "C++: User data is: " << env->GetStringUTFChars(result, NULL) << std::endl;
+
+ return result;
+ }
+
diff --git a/jni/src/main/cpp/com_baeldung_jni_ExampleObjectsJNI.h b/jni/src/main/cpp/com_baeldung_jni_ExampleObjectsJNI.h
new file mode 100644
index 0000000000..28cb782eed
--- /dev/null
+++ b/jni/src/main/cpp/com_baeldung_jni_ExampleObjectsJNI.h
@@ -0,0 +1,29 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class com_baeldung_jni_ExampleObjectsJNI */
+
+#ifndef _Included_com_baeldung_jni_ExampleObjectsJNI
+#define _Included_com_baeldung_jni_ExampleObjectsJNI
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_baeldung_jni_ExampleObjectsJNI
+ * Method: createUser
+ * Signature: (Ljava/lang/String;D)Lcom/baeldung/jni/UserData;
+ */
+JNIEXPORT jobject JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_createUser
+ (JNIEnv *, jobject, jstring, jdouble);
+
+/*
+ * Class: com_baeldung_jni_ExampleObjectsJNI
+ * Method: printUserData
+ * Signature: (Lcom/baeldung/jni/UserData;)V
+ */
+JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleObjectsJNI_printUserData
+ (JNIEnv *, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/jni/src/main/cpp/com_baeldung_jni_ExampleParametersJNI.cpp b/jni/src/main/cpp/com_baeldung_jni_ExampleParametersJNI.cpp
new file mode 100644
index 0000000000..319b85f592
--- /dev/null
+++ b/jni/src/main/cpp/com_baeldung_jni_ExampleParametersJNI.cpp
@@ -0,0 +1,34 @@
+#include "com_baeldung_jni_ExampleParametersJNI.h"
+#include
+#include
+
+/*
+ * Class: com_baeldung_jni_ExampleParametersJNI
+ * Method: sumIntegers
+ * Signature: (II)J
+ */
+JNIEXPORT jlong JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sumIntegers (JNIEnv* env, jobject thisObject, jint first, jint second){
+ std::cout << "C++: The numbers received are : " << first << " and " << second << std::endl;
+ return (long)first + (long)second;
+}
+
+
+/*
+ * Class: com_baeldung_jni_ExampleParametersJNI
+ * Method: sayHelloToMe
+ * Signature: (Ljava/lang/String;Z)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sayHelloToMe (JNIEnv* env, jobject thisObject, jstring name, jboolean isFemale){
+ const char* nameCharPointer = env->GetStringUTFChars(name, NULL);
+ std::cout << "C++: The string received is: " << nameCharPointer << std::endl;
+ std::string title;
+ if(isFemale){
+ title = "Ms. ";
+ }
+ else{
+ title = "Mr. ";
+ }
+
+ std::string fullName = title + nameCharPointer;
+ return env->NewStringUTF(fullName.c_str());
+}
diff --git a/jni/src/main/cpp/com_baeldung_jni_ExampleParametersJNI.h b/jni/src/main/cpp/com_baeldung_jni_ExampleParametersJNI.h
new file mode 100644
index 0000000000..58b9a2ca2f
--- /dev/null
+++ b/jni/src/main/cpp/com_baeldung_jni_ExampleParametersJNI.h
@@ -0,0 +1,29 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class com_baeldung_jni_ExampleParametersJNI */
+
+#ifndef _Included_com_baeldung_jni_ExampleParametersJNI
+#define _Included_com_baeldung_jni_ExampleParametersJNI
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_baeldung_jni_ExampleParametersJNI
+ * Method: sumIntegers
+ * Signature: (II)J
+ */
+JNIEXPORT jlong JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sumIntegers
+ (JNIEnv*, jobject, jint, jint);
+
+/*
+ * Class: com_baeldung_jni_ExampleParametersJNI
+ * Method: sayHelloToMe
+ * Signature: (Ljava/lang/String;Z)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_baeldung_jni_ExampleParametersJNI_sayHelloToMe
+ (JNIEnv*, jobject, jstring, jboolean);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/jni/src/main/cpp/com_baeldung_jni_HelloWorldJNI.cpp b/jni/src/main/cpp/com_baeldung_jni_HelloWorldJNI.cpp
new file mode 100644
index 0000000000..d2001ebdac
--- /dev/null
+++ b/jni/src/main/cpp/com_baeldung_jni_HelloWorldJNI.cpp
@@ -0,0 +1,13 @@
+#include "com_baeldung_jni_HelloWorldJNI.h"
+#include
+
+/*
+ * Class: com_baeldung_jni_HelloWorldJNI
+ * Method: sayHello
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_baeldung_jni_HelloWorldJNI_sayHello (JNIEnv* env, jobject thisObject) {
+ std::string hello = "Hello from C++ !!";
+ std::cout << hello << std::endl;
+ return env->NewStringUTF(hello.c_str());
+}
\ No newline at end of file
diff --git a/jni/src/main/cpp/com_baeldung_jni_HelloWorldJNI.h b/jni/src/main/cpp/com_baeldung_jni_HelloWorldJNI.h
new file mode 100644
index 0000000000..fbdd4cc8f7
--- /dev/null
+++ b/jni/src/main/cpp/com_baeldung_jni_HelloWorldJNI.h
@@ -0,0 +1,21 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class com_baeldung_jni_HelloWorldJNI */
+
+#ifndef _Included_com_baeldung_jni_HelloWorldJNI
+#define _Included_com_baeldung_jni_HelloWorldJNI
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: com_baeldung_jni_HelloWorldJNI
+ * Method: sayHello
+ * Signature: ()V
+ */
+JNIEXPORT jstring JNICALL Java_com_baeldung_jni_HelloWorldJNI_sayHello
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/jni/src/main/cpp/generateNativeLib.bat b/jni/src/main/cpp/generateNativeLib.bat
new file mode 100644
index 0000000000..73fb29fa66
--- /dev/null
+++ b/jni/src/main/cpp/generateNativeLib.bat
@@ -0,0 +1,6 @@
+REM Create the header with javac -h . ClassName.java
+REM Remember to set your JAVA_HOME env var
+g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
+g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_baeldung_jni_ExampleParametersJNI.cpp -o com_baeldung_jni_ExampleParametersJNI.o
+g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_baeldung_jni_ExampleObjectsJNI.cpp -o com_baeldung_jni_ExampleObjectsJNI.o
+g++ -shared -o ..\..\..\native\win32\native.dll com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o -Wl,--add-stdcall-alias
\ No newline at end of file
diff --git a/jni/src/main/cpp/generateNativeLib.sh b/jni/src/main/cpp/generateNativeLib.sh
new file mode 100755
index 0000000000..4a90d1ee04
--- /dev/null
+++ b/jni/src/main/cpp/generateNativeLib.sh
@@ -0,0 +1,7 @@
+# Create the header with javac -h . ClassName.java
+# Remember to set your JAVA_HOME env var
+g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
+g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux com_baeldung_jni_ExampleParametersJNI.cpp -o com_baeldung_jni_ExampleParametersJNI.o
+g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux com_baeldung_jni_ExampleObjectsJNI.cpp -o com_baeldung_jni_ExampleObjectsJNI.o
+g++ -shared -fPIC -o ../../../native/linux_x86_64/libnative.so com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o -lc
+# Don't forget to set java.library.path to point to the folder where you have the libnative you're loading.
\ No newline at end of file
diff --git a/jni/src/main/cpp/generateNativeLibMac.sh b/jni/src/main/cpp/generateNativeLibMac.sh
new file mode 100755
index 0000000000..d11dcc7c01
--- /dev/null
+++ b/jni/src/main/cpp/generateNativeLibMac.sh
@@ -0,0 +1,6 @@
+# Create the header with javac -h . ClassName.java
+# Remember to set your JAVA_HOME env var
+g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
+g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_ExampleParametersJNI.cpp -o com_baeldung_jni_ExampleParametersJNI.o
+g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_ExampleObjectsJNI.cpp -o com_baeldung_jni_ExampleObjectsJNI.o
+g++ -dynamiclib -o ../../../native/macos/libnative.dylib com_baeldung_jni_HelloWorldJNI.o com_baeldung_jni_ExampleParametersJNI.o com_baeldung_jni_ExampleObjectsJNI.o -lc
\ No newline at end of file
diff --git a/jni/src/main/java/com/baeldung/jni/ExampleObjectsJNI.java b/jni/src/main/java/com/baeldung/jni/ExampleObjectsJNI.java
new file mode 100644
index 0000000000..b8ebfb3cd5
--- /dev/null
+++ b/jni/src/main/java/com/baeldung/jni/ExampleObjectsJNI.java
@@ -0,0 +1,19 @@
+package com.baeldung.jni;
+
+public class ExampleObjectsJNI {
+
+ static {
+ System.loadLibrary("native");
+ }
+
+ public static void main(String[] args) {
+ ExampleObjectsJNI instance = new ExampleObjectsJNI();
+ UserData newUser = instance.createUser("John Doe", 450.67);
+ instance.printUserData(newUser);
+ }
+
+ public native UserData createUser(String name, double balance);
+
+ public native String printUserData(UserData user);
+
+}
diff --git a/jni/src/main/java/com/baeldung/jni/ExampleParametersJNI.java b/jni/src/main/java/com/baeldung/jni/ExampleParametersJNI.java
new file mode 100644
index 0000000000..f4553b7773
--- /dev/null
+++ b/jni/src/main/java/com/baeldung/jni/ExampleParametersJNI.java
@@ -0,0 +1,20 @@
+package com.baeldung.jni;
+
+public class ExampleParametersJNI {
+
+ static {
+ System.loadLibrary("native");
+ }
+
+ public static void main(String[] args) {
+ System.out.println("Java: My full name: " + new ExampleParametersJNI().sayHelloToMe("Martin", false));
+ long sumFromNative = new ExampleParametersJNI().sumIntegers(456, 44);
+ System.out.println("Java: The sum coming from native code is: " + sumFromNative);
+ }
+
+ // Declare another method sumIntegers that receives two integers and return a long with the sum
+ public native long sumIntegers(int first, int second);
+
+ // Declare another method sayHelloToMe that receives the name and gender and returns the proper salutation
+ public native String sayHelloToMe(String name, boolean isFemale);
+}
diff --git a/jni/src/main/java/com/baeldung/jni/HelloWorldJNI.java b/jni/src/main/java/com/baeldung/jni/HelloWorldJNI.java
new file mode 100644
index 0000000000..a351238900
--- /dev/null
+++ b/jni/src/main/java/com/baeldung/jni/HelloWorldJNI.java
@@ -0,0 +1,15 @@
+package com.baeldung.jni;
+
+public class HelloWorldJNI {
+
+ static {
+ System.loadLibrary("native");
+ }
+
+ public static void main(String[] args) {
+ new HelloWorldJNI().sayHello();
+ }
+
+ // Declare a native method sayHello() that receives no arguments and returns void
+ public native String sayHello();
+}
diff --git a/jni/src/main/java/com/baeldung/jni/UserData.java b/jni/src/main/java/com/baeldung/jni/UserData.java
new file mode 100644
index 0000000000..5b93f9dfb0
--- /dev/null
+++ b/jni/src/main/java/com/baeldung/jni/UserData.java
@@ -0,0 +1,11 @@
+package com.baeldung.jni;
+
+public class UserData {
+
+ public String name;
+ public double balance;
+
+ public String getUserInfo() {
+ return "[name]=" + name + ", [balance]=" + balance;
+ }
+}
diff --git a/jni/src/test/java/com/baeldung/jni/JNINativeTests.java b/jni/src/test/java/com/baeldung/jni/JNINativeTests.java
new file mode 100644
index 0000000000..42e572d41b
--- /dev/null
+++ b/jni/src/test/java/com/baeldung/jni/JNINativeTests.java
@@ -0,0 +1,58 @@
+package com.baeldung.jni;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class JNINativeTests {
+
+ @Before
+ public void setup() {
+ System.loadLibrary("native");
+ }
+
+ @Test
+ public void whenNativeHelloWorld_thenOutputIsAsExpected() {
+ HelloWorldJNI helloWorld = new HelloWorldJNI();
+ String helloFromNative = helloWorld.sayHello();
+ assertTrue(!helloFromNative.isEmpty() && helloFromNative.equals("Hello from C++ !!"));
+ }
+
+ @Test
+ public void whenSumNative_thenResultIsArithmeticallyCorrect() {
+ ExampleParametersJNI parametersNativeMethods = new ExampleParametersJNI();
+ assertTrue(parametersNativeMethods.sumIntegers(200, 400) == 600L);
+ }
+
+ @Test
+ public void whenSayingNativeHelloToMe_thenResultIsAsExpected() {
+ ExampleParametersJNI parametersNativeMethods = new ExampleParametersJNI();
+ assertEquals(parametersNativeMethods.sayHelloToMe("Orange", true), "Ms. Orange");
+ }
+
+ @Test
+ public void whenCreatingNativeObject_thenObjectIsNotNullAndHasCorrectData() {
+ String name = "Iker Casillas";
+ double balance = 2378.78;
+ ExampleObjectsJNI objectsNativeMethods = new ExampleObjectsJNI();
+ UserData userFromNative = objectsNativeMethods.createUser(name, balance);
+ assertNotNull(userFromNative);
+ assertEquals(userFromNative.name, name);
+ assertTrue(userFromNative.balance == balance);
+ }
+
+ @Test
+ public void whenNativeCallingObjectMethod_thenResultIsAsExpected() {
+ String name = "Sergio Ramos";
+ double balance = 666.77;
+ ExampleObjectsJNI objectsNativeMethods = new ExampleObjectsJNI();
+ UserData userData = new UserData();
+ userData.name = name;
+ userData.balance = balance;
+ assertEquals(objectsNativeMethods.printUserData(userData), "[name]=" + name + ", [balance]=" + balance);
+ }
+
+}