diff --git a/.travis.yml b/.travis.yml index 13f74519..b17fe316 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,18 @@ -language: node_js -node_js: - - "0.11" - - "0.10" - - "0.8" +language: java +jdk: + - oraclejdk8 + - oraclejdk7 + - openjdk6 +env: + - NODE_VERSION="0.11" + - NODE_VERSION="0.10" + - NODE_VERSION="0.8" +before_install: + - nvm install $NODE_VERSION +before_script: + - npm install +script: + - npm test notifications: email: on_success: "never" diff --git a/README.md b/README.md index 260efcca..7b078d24 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,20 @@ npm test _NOTE: You will need node-gyp installed using "npm install -g node-gyp"_ +### Java 1.8 support + +Manual compilation for Java 1.8 support requires additional steps: + +```bash +./compile-java-code.sh +./compile-java8-code.sh +node-gyp configure build +npm test +npm test8 +``` + +Java 1.8 language features can be used in Java classes only if a Java 1.8 JRE is available. The script compile-java8-code.sh is used only to compile java classes used in the 'test8' unit tests, but these classes are checked into the test8/ directory. Note that unit tests in the test8/ directory will pass (by design) if run against a Java 1.6 or 1.7 JRE, provided that a java.lang.UnsupportedClassVersionError is caught with the message 'Unsupported major.minor version 52.0' (the expected behavior when Java 1.8 language features are used in an older JRE). + ## Installation node-webkit ```bash @@ -208,7 +222,7 @@ __Example__ var Test = java.import('Test'); Test.someStaticMethodSync(5); console.log(Test.someStaticField); - + var value1 = Test.NestedEnum.Value1; var test = new Test(); diff --git a/compile-java8-code.sh b/compile-java8-code.sh new file mode 100755 index 00000000..af3015e2 --- /dev/null +++ b/compile-java8-code.sh @@ -0,0 +1,14 @@ +#!/bin/bash -e + +# This script must be run on a Mac due to its reliance on /usr/libexec/java_home +# to find a JDK 1.8 installation. Note that this script will work correctly on +# a mac with JDK 1.8 installed, even if JAVA_HOME currently points to a 1.7 +# or earlier JDK. +# This script is run manually by maintainers of this project, who add the +# the generated .class files to source control. + +JAVA_VERSION=1.8 +JDK8_HOME=$(/usr/libexec/java_home -v ${JAVA_VERSION}) + +cd test8 +${JDK8_HOME}/bin/javac -source ${JAVA_VERSION} *.java diff --git a/package.json b/package.json index 358dbc77..1703677b 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "nodeunit": "0.9.0" }, "scripts": { - "test": "nodeunit test", + "test": "nodeunit test test8", "postinstall": "node postInstall.js" }, "main": "./index.js" diff --git a/src/java.cpp b/src/java.cpp index f4169990..b38247eb 100644 --- a/src/java.cpp +++ b/src/java.cpp @@ -161,7 +161,7 @@ v8::Local Java::createJVM(JavaVM** jvm, JNIEnv** env) { } JNI_GetDefaultJavaVMInitArgs(&args); - args.version = JNI_VERSION_1_6; + args.version = JNI_BEST_VERSION; args.ignoreUnrecognized = false; args.options = vmOptions; args.nOptions = vmOptionsCount; @@ -1050,6 +1050,12 @@ NAN_METHOD(Java::instanceOf) { void EIO_CallJs(uv_work_t* req) { } +static std::string int_to_string(int i) { + char buf[32]; + snprintf(buf, sizeof(buf), "%d", i); + return std::string(buf); +} + #if NODE_MINOR_VERSION >= 10 void EIO_AfterCallJs(uv_work_t* req, int status) { #else @@ -1062,10 +1068,10 @@ void EIO_AfterCallJs(uv_work_t* req) { dynamicProxyData->result = NULL; JNIEnv* env; - int ret = dynamicProxyData->java->getJvm()->GetEnv((void**)&env, JNI_VERSION_1_6); + int ret = dynamicProxyData->java->getJvm()->GetEnv((void**)&env, JNI_BEST_VERSION); if (ret != JNI_OK) { dynamicProxyData->throwableClass = "java/lang/IllegalStateException"; - dynamicProxyData->throwableMessage = "Could not retrieve JNIEnv: jvm->GetEnv returned " + ret; + dynamicProxyData->throwableMessage = "Could not retrieve JNIEnv: jvm->GetEnv returned " + int_to_string(ret); dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } diff --git a/src/java.h b/src/java.h index 2e6ca61c..e8074757 100644 --- a/src/java.h +++ b/src/java.h @@ -8,6 +8,12 @@ #include #include +#ifdef JNI_VERSION_1_8 +#define JNI_BEST_VERSION JNI_VERSION_1_8 +#else +#define JNI_BEST_VERSION JNI_VERSION_1_6 +#endif + class Java : public node::ObjectWrap { public: static void Init(v8::Handle target); diff --git a/src/utils.cpp b/src/utils.cpp index ad66383b..97dfedbb 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -127,11 +127,11 @@ std::string javaMethodCallToString(JNIEnv *env, jobject obj, jmethodID methodId, JNIEnv* javaGetEnv(JavaVM* jvm, jobject classLoader) { JNIEnv *env = NULL; - int ret = jvm->GetEnv((void**)&env, JNI_VERSION_1_6); + int ret = jvm->GetEnv((void**)&env, JNI_BEST_VERSION); if (ret == JNI_EDETACHED) { JavaVMAttachArgs attachArgs; - attachArgs.version = JNI_VERSION_1_6; + attachArgs.version = JNI_BEST_VERSION; attachArgs.name = NULL; attachArgs.group = NULL; jvm->AttachCurrentThread((void**)&env, &attachArgs); diff --git a/test8/TestLambda$IntegerMath.class b/test8/TestLambda$IntegerMath.class new file mode 100644 index 00000000..715fed7d Binary files /dev/null and b/test8/TestLambda$IntegerMath.class differ diff --git a/test8/TestLambda.class b/test8/TestLambda.class new file mode 100644 index 00000000..a56ab0ac Binary files /dev/null and b/test8/TestLambda.class differ diff --git a/test8/TestLambda.java b/test8/TestLambda.java new file mode 100644 index 00000000..89d52880 --- /dev/null +++ b/test8/TestLambda.java @@ -0,0 +1,18 @@ +class TestLambda +{ + public TestLambda() {} + + interface IntegerMath { + int op(int a, int b); + } + + public int testLambdaAddition(Integer x, Integer y) { + IntegerMath addition = (a, b) -> a + b; + return addition.op(x, y); + } + + public int testLambdaSubtraction(Integer x, Integer y) { + IntegerMath subtraction = (a, b) -> a - b; + return subtraction.op(x, y); + } +} diff --git a/test8/testLambda.js b/test8/testLambda.js new file mode 100644 index 00000000..70e0362d --- /dev/null +++ b/test8/testLambda.js @@ -0,0 +1,27 @@ +var java = require("../testHelpers").java; + +var nodeunit = require("nodeunit"); +var util = require("util"); + +exports['Java8'] = nodeunit.testCase({ + "call methods of a class that uses lambda expressions": function(test) { + try { + var TestLambda = java.import('TestLambda'); + var lambda = new TestLambda(); + var sum = lambda.testLambdaAdditionSync(23, 42); + test.equal(sum, 65); + var diff = lambda.testLambdaSubtractionSync(23, 42); + test.equal(diff, -19); + } + catch (err) { + var unsupportedVersion = err.toString().match(/Unsupported major.minor version 52.0/) + test.ok(unsupportedVersion); + if (unsupportedVersion) + console.log('JRE 1.8 not available'); + else + console.error('Java8 test failed with unknown error:', err); + } + test.done(); + } +}); + diff --git a/testHelpers.js b/testHelpers.js index e082864e..2f0cee34 100644 --- a/testHelpers.js +++ b/testHelpers.js @@ -5,5 +5,6 @@ java.options.push("-Djava.awt.headless=true"); java.classpath.push("test/"); java.classpath.push("test/commons-lang3-3.1.jar"); +java.classpath.push("test8/"); module.exports.java = java;