What does the 'require "java"' statement do in JRuby scripts? - java

I read about Java interoperability in Ruby, so using JRuby is an obvious choice. But somehow I don't really grasp the idea behind require 'java'. The documentation says:
... will give you access to any bundled Java libraries (classes within your java class path). However, this will not give you access to any non-bundled libraries.
Are there any more elaborated explanations?
To be more precise I don't understand why the following code works without require "java":
$ export CLASSPATH=".:lib/opennlp-tools-1.6.0.jar"
$ jruby -e 't = Java::OpennlpToolsTokenize::SimpleTokenizer.new; puts t.tokenize("I went to school").to_a'

There are two parts to this question which need answering and some clarification we should make to our documentation (I made an attempt already in https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby):
require 'java'. It loads the ability to load java classes and treat them as if they were Ruby objects/classes. However, Since JRuby 1.7.x, JRuby internally needs to require 'java' so it has already required 'java' by the time your expression is evaluated. So technically it is true that "require 'java'" loads Java interoperability, but since our kernel does this now it is largely a no-op by the time you call it (see return value of the require). We still recommend putting it at the top of any file where you use Java interop. just so it is documented in your code. Also, the fact that it happens to be loaded is more of an impl detail and not a semantic detail (e.g. in the distant future we maybe won't require it in our kernel).
Unclear verbiage: "However, this will not give you access to any non-bundled libraries.". So if you want to access a library not in your CLASSPATH (this was stipulated in the parenthesis) you need to add them to your LOAD_PATH (or via direct require'ing). I tweaked that sentence to hopefully make it more clear.

Related

java - Compile code on client side without JDK

I have a question which I'm pretty confused from.
I am aware of the differences between Java Runtime Enviroment and Java Developement Kit.
I'm writing a program that uses the ToolProvider.getSystemJavaCompiler() method to compile java code from within the code.
Now, I've been answered that I can't compile code from client side if my client doesn't have JDK installed. My main question is, how can I do that? I don't want my clients having to install JDK on their computer just to run my program.
Thanks in advance!
You need to compile it on your system, and distribute the class file of corresponding java source file to anyone.
That class file doesn't require JDK but JRE must be installed on that system to run the class file.
If you want to compile code, you need a compiler, so if the user can't be expected to have the compiler you need, you'll simply have to bundle it.
I really can't say I know how to bundle the standard javac compiler, though it's probably possible, strictly speaking, to find the Jar file that contains it and bundle that along with your code. No idea how robust such a solution would be, though.
But depending on your needs, you may not need the standard javac. There are tons of byte-code generation libraries out there, with more or less high-level functionality. I wouldn't really want to recommend anything that I have no personal experience with, but examples include Byte Buddy or ASM. You could probably use ABCL too.
Eclipse's compiler is worth a look as well.
There is also an so question here.
So there really is no way to do what it is you are wanting to do unless you bundle the compiler itself with you application, or unless you find a library that has all of the Java compiler code in it already so it doesn't have to use the JDK compiler, you will not get what you want, and what you want is the ability to turn a String containing source code into a Java class.
I do not understand what you wish to accomplish, but the BEST option I can give you is asm. If you are up for the task, you can manually write new classes at runtime without the presence of the JDK compiler. HOWEVER, this does not involve you using a String full of source code and turning it into a Class object. This is you working at the low level with the Java bytecode for the most part.
This tutorial can get you started:
https://www.javaworld.com/article/2071777/design-patterns/add-dynamic-java-code-to-your-application.html
And here is the Java documentation for class files. You can use this to expand on what you learned from the first link:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
That is the only instance creating classes on the fly that I can give you. That being said, you could try writing your own Java compiler that can turn source code into classes without ever getting the Java compiler, but at that point you are literally recreating the Java compiler yourself, and I assure you that is no easy feat for one person.

Diference between jdk/bin/java and jdk/jre/bin/java

Making somes tests this week i found this situation:
When i run the tomcat using the java executable in jdk/jre/bin/java the performance is a lot betther than when i run with jdk/bin/java.
The question is: Someone knows why the jdk package delivers 2 java executables and what is the difference between them that justifies the performance difference?
I'm late to the party, but... I came here looking for the difference between the several java variants within OpenJDK. I only ended up with a few clarifications and additional questions to the "what's the difference between them" part of the question; hope it's helpful.
Looking inside the OpenJDK (I'm using OpenJDK 1.7.0) base directory I see three javas, all with different hash-sums:
bin/java, binary
jre-abrt/bin/java, binary; assuming ABRT is Automatic Bug Reporting Tool
jre/bin/java, a shell script that execs the jre-abrt/bin/java variant, in one of two different ways (more below).
The binary variants above have the same file-size and creation-time (in my version and system, anyway) but 4 bytes differ between the two files (I haven't looked much further -- this is the other part of your question -- but they are different, and it doesn't look like an ASCII string, for instance).
The script variant is the one you're saying is faster, which seems counterintuitive because it seems to be doing more. (Or perhaps you're only seeing the time to execute the script and not the exec'd java command?). The script checks to see if an ABRT shared-object file exists, and if so it passes (as -agentpath...) the .so and abrt=on. Again, this seems like it should be nothing but more work... assuming use of ABRT.
If you're still interested in this topic, perhaps it would be interesting to see the following:
what path in that script you're taking (check for existence of /usr/lib64/libabrt-java-connector.so or whatever is in your jre/bin/java script)
if directly executing the third variant (jre-abrt/bin/java) is faster
what else is being touched in both of these cases -- like inotify or strace or something, but this is probably enormous for a service like this.
the java.exe files are actually the same. The JDK is the Java Development Kit, which includes all of the java executables you need to develop applications.
The JRE is the Java Runtime Environment, which includes what you need to run Java applications
So for running the application in a deployed mode, you would need only the JRE, as end users are likely to have only a JRE and not a JDK.

How can I monkey patch JRuby to give it a pseudo file system?

Previously I was trying to give the Java engine for JavaScript - rhino - a pseudo file system and I have had success (jszip maven plugin)
I now am turning my attention to the SASS compiler
I have integrated JRuby into my Maven plugin and I can call through to the SASS compiler just fine, so now the final step (before the great refactoring from hack-land to maintainable code) is to fake out the paths that JRuby sees,
My feeling is that I will not be able to reuse my Rhino trick (where I remap the java.io.File class adapter in the Rhino scope) as Ruby in general does not have adapter layers to correct for the differences between different Ruby VMs
So my next thought was monkey patch... But I am unsure how big a job that would be...
With JavaScript I just had to fake java.io.File, java.io.FileReader, java.io.FileWriter, java.io.FileInputStream, java.io.FileOutputStream
How much would I need to monkey patch in the Ruby runtime... Or am I better using an ASM based rewriting classloader to pull the rug from under JRuby itself (where I risk breaking legitimate File use to load eg Gems)
An answer to my specific problem with regards to the SASS compiler, but not an answer to the general question of what to do to monkey-patch JRuby to give it a fake file system.
It turns out that Sass has a concept of an Sass::Importer::Base which is the base class for resolving .scss and .sass files. So all I needed to do is create my own implementation which delegates to my virtual file system and configure the options passed to Sass::Engine.new such that the default file-system based importer is replaced with my Importer implementation.
Seems to be working though I have had some issues trying to get it to compile Foundation 3 perhaps due to it relying on Compass which contrasts with the testing experience I had for LESS support, where Bootstrap is stand-alone.
Update
With regard to the ASM based rewriting classloader. Perhaps the trick in that approach is to use AspectC to modify only those classes in the JRuby runtime. In other words, only apply the aspect if the class extends RubyObject. That should retain the legitimate needs of JRuby to load the ruby source code, while giving the embedded VM the fake file system.
With regard to Monkey-patching, it seems there would be a lot of work filling in all the equivalent methods that Ruby's File APIs provide in order to ensure that the monkey patch holds, and especially given that we don't know the exact footprint of what APIs the SASS compiler will use.
So, I guess the full answer is: "You don't want to do either monkey-patching or ASM rewriting as the library you want to use provides a nice abstraction to allow feeding it the virtual filesystem anyway"

Conditional compilation with Java and ant

I have a problem wit the software I'm working on.
We are accessing Windows system calls via JNA, and we have to define some Windows structure (Java class that extends the JNA Structure) to be able to access them.
The application has to work with 32-bit and 64-bit architecture, but the problem with the structures is that attributes in them change based on the system architecture (from int to long for example).
Is there an easy (and sane) way to do conditional compilation a-la #ifdef in Java using ant? Are there any other ways to achieve this kind of conditional #ifdef?
The other way we are contemplating is to create a general interface, create two different structures for 32-bit and 64-bit, and then handle the different case with some if-else.
Thanks.
Would the Ant condition clauses not do
http://ant.apache.org/manual/Tasks/condition.html
UPDATE:
I think I finally got what you're trying to do. Looking at the javac man here I don't think the Java compiler will let you do that, regardless of the conditions you put in Ant. Either way I found a post on stackoverflow on determining the system architecture and a thread on the sun forums that you might find helpful.
wwyt is a conditional compilation pre-processor for Java language. It accepts (commented out) directives like #if, #else, .... etc. It's a Windows command line tool and can be used as a pre-processor before calling Ant to make the build. (And after the build, it can restore the converted files back to their original state.) Not sure if this helps, just so you know. Link is here: http://www.adarian.com/wwyt

Combining Java and C without gcj -- move C to Java or Java to C?

First, I have no experience doing this. But like the beginning of any good program, I have problem that I need to fix, so I'm willing to learn.
So many of you are probably already familiar with pdftk, the handy utility for handling various pdf-related tasks. So far as I can tell, most of these features are available in much newer, lighter libraries/extensions, except the one I need (and probably the only reason it still exists): merging form data files (fdf and xfdf) with a form PDF and getting a new file as the output.
The problem is that my server doesn't have gcj, which is fundamental to build/compile pdftk. I don't know if it's because I'm on Solaris or if it's for some other sysadmin-level reason, but I'm not getting gcj anytime soon. And there are no pre-compiled binaries for Solaris as far as I can find.
So I'm thinking that the MAKE file and C code can be rewritten to import the Java library (very ancient version of itext) directly, via javac.
But I'm not sure where to really start. All I know is:
I want a binary when I'm done, so that there won't be a need for a Java VM on every use.
The current app uses GCJ.
So my first thought was "Oh this is easy, I can probably just call the classes with some other C-based method", but instead of finding a simple method for doing this, I'm finding tons of lengthy posts on the various angles that this can be approached, etc.
Then I found a page on Sun's site on how to call other languages (like C) in a Java class. But the problems with that approach are:
I'd have to write a wrapper for the wrapper
I'd probably be better off skipping that part and writing the whole thing in Java
I ain't ready for that just yet if I can just import the classes with what is already there
I'm not clear on if I can compile and get a binary at the end or if I'm trapped in Java being needed every time.
Again, I apologize for my ignorance. I just need some advice and examples of how one would replace GCJ dependent C code with something that works directly with Java.
And of course if I'm asking one of those "if we could do that, we'd be rich already" type questions, let me know.
I'm not sure what you are looking for exactly, so I provided several answers.
If you have java code that needs to run, you must:
Run it in a jvm. You can start that vm within your own custom c-code, but it is still using a jvm
Rewrite it in another language.
Compile with an ahead-of-time compiler (eg gcj)
Incidentally, you could compile a copy of gcj in your home folder and use that. I believe the magic switch is --enable-languages=java,c (see: here for more)
If you have c-code you want to call from java, you have four options:
Java Native Interface (JNI). It seems you found this
Java Native Access (JNA). This is slower than JNI, but requires less coding and no wrapper c-code. It does require a jar and a library
Create a CLI utility and use Runtime.Exec(...) to call it.
Use some sort of Inter Process Communication to have the Java code ask the c-code to perform the operation and return the result.
Additional platform dependent options
Use JACOB (win32 only: com access)
I am not sure if I understand what you are looking for.
If you are looking to incorporate the C code into Java to make a native binary without the gcj, I think you are out of luck. You can include the C in Java, but it would be a primarily Java program meaning you would need the JVM on each run. Is there anything stopping you from compiling the gcj yourself?

Categories

Resources