From 398fe0dd06870bab4ad8877a3e1085443ab2f713 Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Fri, 17 Oct 2014 10:42:55 -0700 Subject: [PATCH 1/8] Experimental hacks to use JDK8. Mac only, no backward compatibity for JDK6. These changes seem to be sufficient to make JDK8 work. This module's unit tests pass, and I have evidence that gremlin-node now accepts references to classes that were compiled for Java 8. We now have to figure out how to maintain backward compatiblity for JDK6. Perhaps we can simply detect which JDK is installed in JAVA_HOME and compile for it? --- compile-java-code.sh | 4 ++-- src/java.cpp | 12 +++++++++--- src/utils.cpp | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/compile-java-code.sh b/compile-java-code.sh index bc52d6fe..b510f55a 100755 --- a/compile-java-code.sh +++ b/compile-java-code.sh @@ -1,7 +1,7 @@ #!/bin/bash -e -JAVA_VERSION=1.6 -JAVAC_OPTS="-source ${JAVA_VERSION} -target ${JAVA_VERSION} -bootclasspath /opt/jdk1.6.0_45/jre/lib/rt.jar" +JAVA_VERSION=1.8 +JAVAC_OPTS="-source ${JAVA_VERSION} -target ${JAVA_VERSION}" -bootclasspath ${JAVA_HOME}/jre/lib/rt.jar cd test javac ${JAVAC_OPTS} *.java diff --git a/src/java.cpp b/src/java.cpp index f4169990..625b2c82 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_VERSION_1_8; 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_VERSION_1_8); 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/utils.cpp b/src/utils.cpp index ad66383b..67b08798 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_VERSION_1_8); if (ret == JNI_EDETACHED) { JavaVMAttachArgs attachArgs; - attachArgs.version = JNI_VERSION_1_6; + attachArgs.version = JNI_VERSION_1_8; attachArgs.name = NULL; attachArgs.group = NULL; jvm->AttachCurrentThread((void**)&env, &attachArgs); From 51f75482408dc74a99eaf3b479e184ec066eeaeb Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Fri, 17 Oct 2014 14:13:16 -0700 Subject: [PATCH 2/8] Somewhat better way to support jdk1.8. There are still problems we have to solve for a general release, but this version should do the right thing for jdk1.6 and jdk1.8. jdk1.7 will work, but it will no longer target 1.6. In addition to fixing the problem with jdk1.7, we also need to change the build system so that .java files are compiled to .class files as part of npm install, instead of checking them in. --- compile-java-code.sh | 18 ++++++++++++++++-- src/java.cpp | 4 ++-- src/java.h | 6 ++++++ src/utils.cpp | 4 ++-- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/compile-java-code.sh b/compile-java-code.sh index b510f55a..9f39931f 100755 --- a/compile-java-code.sh +++ b/compile-java-code.sh @@ -1,7 +1,21 @@ #!/bin/bash -e -JAVA_VERSION=1.8 -JAVAC_OPTS="-source ${JAVA_VERSION} -target ${JAVA_VERSION}" -bootclasspath ${JAVA_HOME}/jre/lib/rt.jar +# JAVA_VERSION=1.6 +# JAVAC_OPTS="-source ${JAVA_VERSION} -target ${JAVA_VERSION}" + +# javac defaults -source and -target +# to it's version. +# We support three versions of javac: 1.6, 1.7, 1.8. +# We want the following mappings: +# javac source target +# 1.6 1.6 1.6 +# 1.7 1.6 1.6 +# 1.8 1.8 1.8 +# Note that the default is only wrong for javac 1.7. +# We'll have to fix this, but for now we do the hack +# of letting javac 1.7 generate with source and target equal to 1.7 + +JAVAC_OPTS="" cd test javac ${JAVAC_OPTS} *.java diff --git a/src/java.cpp b/src/java.cpp index 625b2c82..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_8; + args.version = JNI_BEST_VERSION; args.ignoreUnrecognized = false; args.options = vmOptions; args.nOptions = vmOptionsCount; @@ -1068,7 +1068,7 @@ void EIO_AfterCallJs(uv_work_t* req) { dynamicProxyData->result = NULL; JNIEnv* env; - int ret = dynamicProxyData->java->getJvm()->GetEnv((void**)&env, JNI_VERSION_1_8); + 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 " + int_to_string(ret); 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 67b08798..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_8); + int ret = jvm->GetEnv((void**)&env, JNI_BEST_VERSION); if (ret == JNI_EDETACHED) { JavaVMAttachArgs attachArgs; - attachArgs.version = JNI_VERSION_1_8; + attachArgs.version = JNI_BEST_VERSION; attachArgs.name = NULL; attachArgs.group = NULL; jvm->AttachCurrentThread((void**)&env, &attachArgs); From 9537d9154dabeddc31b5a51dc1f883852ee72903 Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Fri, 17 Oct 2014 14:32:06 -0700 Subject: [PATCH 3/8] Try specifying jdk versions in .travis.yml This may not work, since we don't specify language: java The Travis documentation isn't clear, so let's just try it and see what happens. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 13f74519..f9026163 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,3 +6,7 @@ node_js: notifications: email: on_success: "never" +jdk: + - oraclejdk8 + - oraclejdk7 + - openjdk6 From e367f4cc5c2b02cf9da784e296dd99d245ffe464 Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Fri, 17 Oct 2014 14:37:01 -0700 Subject: [PATCH 4/8] Try specifing language:java in addition to language:node_js. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f9026163..c43fa52c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ node_js: notifications: email: on_success: "never" +language: java jdk: - oraclejdk8 - oraclejdk7 From 0ee560ead42946df755d9f44aa9b31886abb859a Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Fri, 17 Oct 2014 14:48:29 -0700 Subject: [PATCH 5/8] Restore .travis.yml. No more experimentation with it on this branch. Sorry, I should have been testing this on a different branch. --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index c43fa52c..13f74519 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,3 @@ node_js: notifications: email: on_success: "never" -language: java -jdk: - - oraclejdk8 - - oraclejdk7 - - openjdk6 From 7fae226dcd3cc81f93e851e3e56a267089c9b09e Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Mon, 20 Oct 2014 10:48:07 -0700 Subject: [PATCH 6/8] Revert compile-java-code.sh back to version in master. --- compile-java-code.sh | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/compile-java-code.sh b/compile-java-code.sh index 9f39931f..bc52d6fe 100755 --- a/compile-java-code.sh +++ b/compile-java-code.sh @@ -1,21 +1,7 @@ #!/bin/bash -e -# JAVA_VERSION=1.6 -# JAVAC_OPTS="-source ${JAVA_VERSION} -target ${JAVA_VERSION}" - -# javac defaults -source and -target -# to it's version. -# We support three versions of javac: 1.6, 1.7, 1.8. -# We want the following mappings: -# javac source target -# 1.6 1.6 1.6 -# 1.7 1.6 1.6 -# 1.8 1.8 1.8 -# Note that the default is only wrong for javac 1.7. -# We'll have to fix this, but for now we do the hack -# of letting javac 1.7 generate with source and target equal to 1.7 - -JAVAC_OPTS="" +JAVA_VERSION=1.6 +JAVAC_OPTS="-source ${JAVA_VERSION} -target ${JAVA_VERSION} -bootclasspath /opt/jdk1.6.0_45/jre/lib/rt.jar" cd test javac ${JAVAC_OPTS} *.java From 004b2fade5e4b00670dfcbdda4b20515a4819f53 Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Mon, 20 Oct 2014 10:49:42 -0700 Subject: [PATCH 7/8] Add compile-java8-code.sh and test for java8. --- compile-java8-code.sh | 14 +++++++++ package.json | 2 +- test8/TestLambda$IntegerMath.class | Bin 0 -> 195 bytes test8/TestLambda.class | Bin 0 -> 1195 bytes test8/TestLambda.java | 18 ++++++++++++ test8/testLambda.js | 44 +++++++++++++++++++++++++++++ testHelpers.js | 1 + 7 files changed, 78 insertions(+), 1 deletion(-) create mode 100755 compile-java8-code.sh create mode 100644 test8/TestLambda$IntegerMath.class create mode 100644 test8/TestLambda.class create mode 100644 test8/TestLambda.java create mode 100644 test8/testLambda.js 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/test8/TestLambda$IntegerMath.class b/test8/TestLambda$IntegerMath.class new file mode 100644 index 0000000000000000000000000000000000000000..715fed7d71aaefde932b115caa3b44a1f304c353 GIT binary patch literal 195 zcmY*TF%E)25S&He5HM2t0t;=V@dqX*muM{X0|#zUf`{QwA7|kMe3bFDAvQZZlbxM; zy&q2iON;~}frQ|-S3)q8axMw+zP)uNug?t=#s@Zbqb|i!EoyaF0x4nAi&LpBSKMut zJrR;WmP)O;TQ$lUHiYc!&l{zyd{@+5S{Kzn3IW%{)pF<)2JqeHA^6P@vBTJ15Cn!{ F^Z|JDD}?|6 literal 0 HcmV?d00001 diff --git a/test8/TestLambda.class b/test8/TestLambda.class new file mode 100644 index 0000000000000000000000000000000000000000..a56ab0ac164057d024e0175a3a7d7e94e4adfeef GIT binary patch literal 1195 zcmbVMTW=CU6#jvHJx_QHiI=8r%2y20YVC+2)^ZHNknWhaIGl|7!tL?C zMVhP>p6u{Z-{7we!<43DGt{b`6Mn|)7Pp7>sh8#gRjtjC4+*-HzI6E@;HX%ar24{Z zy}=N#w%a~IX%6^15Pg?H?K%^8Aofi^*mUnI*d0GW4Jl|0nKzCjJ#sxh5c1eDymSJ3 z202>RH9W*41yv0-Z1@LXyGgtu6%mBlzU!Zefn+Fz_xenoRcv8fMFKkv5ogR$tkyb< zp-qORkax<#kTh+1#H|UXL#=81Ty+Jz8XDNsa2q)dS>zbjLR-^5b52D)=n|#KKTwe! z_nbyx6rL13qqcV(=X64G{g`dxlpv_iTW%Yc@bmyV+t#jhO?x=2`NObxJ{JFX8MwUO zwl*_gQ@1T{SzS|#rh?}T>vIKJln+DYdK^}%;tIViAWjd828iTMI<3&keC@^;uursM zxJ5E?sf?0LBSX@MHV{RO*8Bw`z~T1hXGFK?`-)f;AFoVR{}z6SQ)IZb$UOc}^E8=f zGO9lmQ}1P>^@(G}k`X!!;!G2gW@sMy{%@p8Ipm2Yf&zsI;*ZczCV?A?Bp%}_o?sbw SNnarSGGU7-(HHDiQTzqhJQr91 literal 0 HcmV?d00001 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..eb167c5d --- /dev/null +++ b/test8/testLambda.js @@ -0,0 +1,44 @@ +var java = require("../testHelpers").java; + +var nodeunit = require("nodeunit"); +var util = require("util"); + +exports['Java8'] = nodeunit.testCase({ + + "create an instance of a class that uses lambda expressions": function(test) { + java.newInstance("TestLambda", function(err, lambda) { + if (err) { + console.log(err); + return; + } + test.ok(lambda); + if (lambda) { + lambda.getClass(function(err, result) { + if (err) { + console.log(err); + return; + } + result.getName(function(err, result) { + if (err) { + console.log(err); + return; + } + test.equal(result, "TestLambda"); + test.done(); + }); + }); + } + }); + }, + + "call methods of a class that uses lambda expressions": function(test) { + 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); + 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; From a9584e03269921ceff4cb33b897ecf0de245c527 Mon Sep 17 00:00:00 2001 From: Jim Lloyd Date: Mon, 20 Oct 2014 13:13:59 -0700 Subject: [PATCH 8/8] Simplify Java8 test & handle Unsupported major.minor vers exception. --- test8/testLambda.js | 51 +++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/test8/testLambda.js b/test8/testLambda.js index eb167c5d..70e0362d 100644 --- a/test8/testLambda.js +++ b/test8/testLambda.js @@ -4,41 +4,24 @@ var nodeunit = require("nodeunit"); var util = require("util"); exports['Java8'] = nodeunit.testCase({ - - "create an instance of a class that uses lambda expressions": function(test) { - java.newInstance("TestLambda", function(err, lambda) { - if (err) { - console.log(err); - return; - } - test.ok(lambda); - if (lambda) { - lambda.getClass(function(err, result) { - if (err) { - console.log(err); - return; - } - result.getName(function(err, result) { - if (err) { - console.log(err); - return; - } - test.equal(result, "TestLambda"); - test.done(); - }); - }); - } - }); - }, - "call methods of a class that uses lambda expressions": function(test) { - 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); + 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(); - }, + } });