Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node-java using wrong JRE on Mountain Lion 10.8.4 #61

Closed
hangarr opened this issue Sep 2, 2013 · 15 comments
Closed

node-java using wrong JRE on Mountain Lion 10.8.4 #61

hangarr opened this issue Sep 2, 2013 · 15 comments

Comments

@hangarr
Copy link
Contributor

hangarr commented Sep 2, 2013

I'm sure this has an easy solution but I haven't been able to figure it out after reviewing the node-java module code.

Environment

  1. Mountain Lion OS X 10.8.4 with Apple Java 1.6 JDK installed
    /System/Library/Java/JavaVirtualMachines/1.6.0.jdk
  2. Oracle Java 1.7 JDK installed
    /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk
  3. JAVA_HOME initialized to Oracle Java 1.7 JDK
    $ echo JAVA_HOME /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home
  4. OS X appears to be looking at the Oracle Java 1.7 JDK
    $ /usr/libexec/java_home /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home
    $ java -version java version "1.7.0_25" Java(TM) SE Runtime Environment (build 1.7.0_25-b15) Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

Installation

  1. Installation in the normal way, e.g.:
    $ export JAVA_HOME=`/usr/libexec/java_home` $ npm install java
    appears to work just fine (no warnings or errors)

Tests

  1. Running this code as "javademo.js"

    var java = require('java'); java.classpath.push("commons-lang3-3.1.jar"); java.classpath.push("commons-io.jar");
    var System = java.import('java.lang.System'); console.log(System.getPropertySync("java.version")); console.log(System.getPropertySync("java.home"));
    appears to work, but note the JRE reported:
    $ node javademo 1.6.0_51 /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
  2. Running code that attempts to import a custom class that was compiled with Oracle Java 1.7:

    var java = require('java'); java.classpath.push("commons-lang3-3.1.jar"); java.classpath.push("commons-io.jar");
    var System = java.import('java.lang.System'); console.log(System.getPropertySync("java.version")); console.log(System.getPropertySync("java.home"));
    java.classpath.push("./lib/java-demo.jar"); var DemoClazz = java.import('com.hangarr.utils.DemoClazz');
    yields the expected version error:
    $ node javademo 1.6.0_51 /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
    /Users/dev/Documents/Workspaces/javaDemo/node_modules/java/lib/nodeJavaBridge.js:16 var clazz = java.findClassSync(name); // TODO: change to Class.forName when ^ Error: Could not create class com.devorg.utils.DemoClazz java.lang.UnsupportedClassVersionError: com/devorg/utils/DemoClazz : Unsupported major.minor version 51.0 (etc.)

What doesn't fix this runtime JRE problem

  1. Setting $JAVA_HOME to the Oracle Java 1.7 path
    $ export JAVA_HOME=`/usr/libexec/java_home` $ node javademo
  2. Manually setting the Apple "CurrentJDK" link
    /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK
    to the Oracle Java 1.7 JDK:
    /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents

Any tips on how to use the 1.7 JRE at runtime would be greatly appreciated. Do I perhaps need to pass some parameter to node.js and then perhaps onto the node-java module via the "javademo.js" script?

Or is this not possible and I need to compile custom Java class with a Java 1.6 target? (That works, by the way.)

Thanks.

@joewhite86
Copy link
Contributor

You compiled node-java with JRE 1.6, after that you change JAVA_HOME.
Instead you should first set JAVA_HOME to 1.7, then do npm install java.

Don't know if the osx-java-1.7 & node-java bug is resolved already.
If not let me know, i have a workaround for this, perhaps i find the time to clean it up and commit it to the repo.

@hangarr
Copy link
Contributor Author

hangarr commented Sep 9, 2013

Hi @joewhite86

Thanks for your response. Unfortunately, the situation is essentially the opposite of what you describe.

I did set JAVA_HOME to 1.7 before "npm install java" and the module is being compiled with 1.7. One can actually be certain of this by the way, because one gets warnings about the JNI API being deprecated if one compiles with 1.6. I also set JAVA_HOME to 1.7 before running a demo script with node.js to test it, e.g. "node javademo". (Just to be clear, I've updated my initial comment because I could see how that could have been confusing.)

The problem appears to be that node-java ignores JAVA_HOME at runtime and picks up the 1.6 JRE. I haven't had time to dig down into the node-java code to see if and how it picks up the path to the JRE at runtime.

I did notice that if one just downloads the Master branch .zip file, there is a "./commons-lang3-node-java.jar" that contains classes that were compiled with 1.5 and a ./src-java/NodeDynamicProxyClass.class that was compiled with 1.6. I don't think these are the problem, but it seems worth noting.

Thanks.

@joewhite86
Copy link
Contributor

Hi @hangarr

Maybe you're right, could be at runtime or compile time. Not sure right now.

The problem is the Path to the java header files is hard coded in binding.gyp. See joewhite86@cd8477f for my "quick & dirty" changes.

Should give you a clue.

@joewhite86
Copy link
Contributor

Would really like to add the patch. My problem is, that the structure of the OSX built-in VM is completely different from standard installs.

I did not find any possibility to add os versions to gyp.

Thats what's needed for Java 1.7 installs:

['OS=="mac"',
  {
    "include_dirs": [
      "<(javahome)/include",
      "<(javahome)/include/darwin"
    ],
    "libraries": [
      "-L<(javahome)/jre/lib/server/",
      "-Wl,-rpath,<(javahome)/jre/lib/server/",
      "-ljvm"
    ]
  }
]

And for built-in Java 1.6:

['OS=="mac"',
  {
    "include_dirs": [
      "/System/Library/Frameworks/JavaVM.framework/Headers"
    ],
    "libraries": [
      "-framework JavaVM"
    ]
  }
]

Putting "include_dirs" of both versions together seems to work, when JAVA_HOME is not set or set to 1.6.
But putting the "libraries" parts together doesn't.

2 warnings generated.
  CXX(target) Release/obj.target/nodejavabridge_bindings/src/javaObject.o
  CXX(target) Release/obj.target/nodejavabridge_bindings/src/javaScope.o
  CXX(target) Release/obj.target/nodejavabridge_bindings/src/methodCallBaton.o
  CXX(target) Release/obj.target/nodejavabridge_bindings/src/nodeJavaBridge.o
  CXX(target) Release/obj.target/nodejavabridge_bindings/src/utils.o
  SOLINK_MODULE(target) Release/nodejavabridge_bindings.node
ld: warning: directory not found for option '-L/System/Library/Frameworks/JavaVM.framework/Home/jre/lib/server/'
ld: library not found for -ljvm
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Any ideas?

@hangarr
Copy link
Contributor Author

hangarr commented Sep 11, 2013

Hi @joewhite86, I do have a couple of ideas. Since of the top of my head I'm not sure which will work in the annoying Mountain Lion 10.8.4 OS X Java 6/Java 7 situation and Mountain Lion/Snow Leopard Java 6 only installation, I'd be willing to test them and get back to you with something.

If I:

  1. Download and unpack the .zip from the Master branch into a standalone <folder>
  2. Make test changes to <binding.gyp>
  3. From inside a test project, do:

$ npm install <folder>

will that be close enough to whatever dev/test setup you are using that whatever I find works is likely to work for your dev/test setup? (I never like to assume these things, even though they are supposed to work...)

Thanks.
Rick

@hangarr hangarr closed this as completed Sep 11, 2013
@hangarr hangarr reopened this Sep 11, 2013
@hangarr
Copy link
Contributor Author

hangarr commented Sep 11, 2013

Hit the wrong button...

@joewhite86
Copy link
Contributor

I cloned the repository with git and executed:

# test installation
npm install
# run tests
nodeunit test

@hangarr
Copy link
Contributor Author

hangarr commented Sep 12, 2013

Hi @joewhite86 - I think I have something that may work. Here's a complete "binding.gyp" that has just a couple of modifications. (The full file is added as a separate comment below)

  1. To the 'conditions' dictionary in the "variables" object add this variable declaration
  "variables": {
     ...
    'conditions': [
      ['OS=="mac"', {
        'javaver%' : "<!(awk -F/ -v h=$JAVA_HOME 'BEGIN {n=split(h, a); print a[2]; exit}')"
      }]

This just grabs the root directory "System" or "Library" from JAVA_HOME. Interestingly enough, although I could do the same thing with sed:

        'javaver%' : "<!( echo $JAVA_HOME | sed 's/\/\([^\/]*\)\(\/.*\)/\1/')"

for some reason the comparison operation in the other section of the binding.gyp file didn't work. I think it may have something to do with how gyp shells out the command and pipes.

  1. Replace the 'OS="mac"' condition in the 'conditions' dictionary of the only object in the "targets" dictionary with this
  "targets": [
    {
       ...
      'conditions': [
         ...
        ['OS=="mac" and javaver=="Library"',
          {
            "include_dirs": [
              "<(javahome)/include",
              "<(javahome)/include/darwin"
            ],
            "libraries": [
              "-L<(javahome)/jre/lib/server",
              "-Wl,-rpath,<(javahome)/jre/lib/server",
              "-ljvm"
            ]
          }
        ],
        ['OS=="mac" and javaver=="System"',
          {
            "include_dirs": [
              "/System/Library/Frameworks/JavaVM.framework/Headers"
            ],
            "libraries": [
              "-framework JavaVM"
            ]
          }
        ],
        ['OS=="mac" and javaver==""',
          {
            "include_dirs": [
              "/System/Library/Frameworks/JavaVM.framework/Headers"
            ],
            "libraries": [
              "-framework JavaVM"
            ]
          }
        ]
    ...
  ]
}

I think this is fairly general and makes sense. If the root directory for JAVA_HOME is "Library" then the Java JRE has to have a *nix/Oracle standard layout and if it is "System" it's a Mac framework (regardless of version 1.6 or before). And if JAVA_HOME is missing, then the only thing to do is to default to the Apple framework.

This seems to work for me with one caveat. I was only up to Node.js 0.10.12 when I started and that turned out to be a 32-bit installation for OS X. I had to update to Node.js 0.10.18 and everything seemed to work.

Also, it turns out Apple has deprecated the Java 1.6 JNI, so "npm install" will throw warnings about this for Java 1.6. I assume this has something to do with the security updates they made in which they disabled their Java 1.6 browser plugin. The resulting install seems to work though.

Does all of this make sense to you? If not, maybe you can suggest further mods?

node-java is turning out to be interesting for my application. Thanks for your assistance and for node-java.

Best,
Rick

@hangarr
Copy link
Contributor Author

hangarr commented Sep 12, 2013

And here's the full binding-gyp that seems to work for me:

{
  "variables": {
    "arch%": "amd64", # linux JVM architecture. See $(JAVA_HOME)/jre/lib/<@(arch)/server/
    'conditions': [
      ['target_arch=="ia32"', {
        'arch%': "i386"
      }],
      ['OS=="win"', {
        'javahome%': "<!(echo %JAVA_HOME%)"
      }],
      ['OS=="linux" or OS=="mac"', {
        'javahome%': "<!(echo $JAVA_HOME)"
      }],
      ['OS=="mac"', {
        'javaver%' : "<!(awk -F/ -v h=$JAVA_HOME 'BEGIN {n=split(h, a); print a[2]; exit}')"
      }]
    ]
  },
  "targets": [
    {
      "target_name": "nodejavabridge_bindings",
      "sources": [
        "src/java.cpp",
        "src/javaObject.cpp",
        "src/javaScope.cpp",
        "src/methodCallBaton.cpp",
        "src/nodeJavaBridge.cpp",
        "src/utils.cpp"
      ],
      "include_dirs": [
        "<(javahome)/include",
      ],
      'conditions': [
        ['OS=="win"',
          {
            'actions': [
              {
                'action_name': 'verifyDeps',
                'inputs': [
                  '<(javahome)/lib/jvm.lib',
                  '<(javahome)/include/jni.h',
                  '<(javahome)/include/win32/jni_md.h'
                ],
                'outputs': ['./build/depsVerified'],
                'action': ['python', 'touch.py'],
                'message': 'Verify Deps'
              }
            ],
            "include_dirs": [
              "<(javahome)/include/win32",
            ],
            "libraries": [
              "-l<(javahome)/lib/jvm.lib"
            ]
          }
        ],
        ['OS=="linux"',
          {
            'actions': [
              {
                'action_name': 'verifyDeps',
                'inputs': [
                  '<(javahome)/jre/lib/<(arch)/server/libjvm.so',
                  '<(javahome)/include/jni.h',
                  '<(javahome)/include/linux/jni_md.h'
                ],
                'outputs': ['./build/depsVerified'],
                'action': [],
                'message': 'Verify Deps'
              }
            ],
            "include_dirs": [
              "<(javahome)/include/linux",
            ],
            "libraries": [
              "-L<(javahome)/jre/lib/<(arch)/server/",
              "-Wl,-rpath,<(javahome)/jre/lib/<(arch)/server/",
              "-ljvm"
            ]
          }
        ],
        ['OS=="mac" and javaver=="Library"',
          {
            "include_dirs": [
              "<(javahome)/include",
              "<(javahome)/include/darwin"
            ],
            "libraries": [
              "-L<(javahome)/jre/lib/server",
              "-Wl,-rpath,<(javahome)/jre/lib/server",
              "-ljvm"
            ]
          }
        ],
        ['OS=="mac" and javaver=="System"',
          {
            "include_dirs": [
              "/System/Library/Frameworks/JavaVM.framework/Headers"
            ],
            "libraries": [
              "-framework JavaVM"
            ]
          }
        ],
        ['OS=="mac" and javaver==""',
          {
            "include_dirs": [
              "/System/Library/Frameworks/JavaVM.framework/Headers"
            ],
            "libraries": [
              "-framework JavaVM"
            ]
          }
        ]
      ]
    }
  ]
}

@joewhite86
Copy link
Contributor

@hangarr
That's awesome!

Works for me on node-0.10.9 with both 1.6 and 1.7.

Thanks Rick

joewhite86 added a commit to joewhite86/node-java that referenced this issue Sep 12, 2013
@hangarr
Copy link
Contributor Author

hangarr commented Sep 14, 2013

@joewhite86 glad to hear it worked. Thanks.

@joewhite86
Copy link
Contributor

Applied another fix for mnm.js #69
The wrong header files were taken, so the java.lang.UnsupportedClassVersionError appeared again for me.

@jsdevel
Copy link
Collaborator

jsdevel commented Dec 21, 2013

@joewhite86 @hangarr Can you clone my fork locally and try building that? Here's the URL: https://github.com/jsdevel/node-java.git

I currently have PR for issue #94 open and I believe it will solve issues like this.

@hangarr
Copy link
Contributor Author

hangarr commented Dec 22, 2013

@jsdevel - I was able to succesfully build and run unit tests of your fork
on my Mountain Lion 10.8.5 installation.. Rick

On Sat, Dec 21, 2013 at 11:55 AM, Joseph Spencer
notifications@github.comwrote:

@joewhite86 https://github.com/joewhite86 @hangarrhttps://github.com/hangarrCan you clone my fork locally and try building that? Here's the URL:
https://github.com/jsdevel/node-java.git

I currently have PR for issue #94https://github.com/joeferner/node-java/issues/94open and I believe it will solve issues like this.


Reply to this email directly or view it on GitHubhttps://github.com//issues/61#issuecomment-31070878
.

@jsdevel
Copy link
Collaborator

jsdevel commented May 23, 2014

@joeferner I think this can be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants