How to include class dependency jar in JRuby? - ruby

I'm having trouble figuring out how to include/import/require mydependency.jar which MyJavaClass (within a MyJavaClass.class file) depends on. MyJavaClass contains many import statements importing classes from mydependency.jar. Everything is in the same directory.
When I run java -cp '.:mydependency.jar' MyJavaClass on the command line, I get no error and by putting some calls in main I can get it to run how I want, but when I run ruby my_ruby_file.rb with JRuby on the command line I get NoClassDefFoundError for the first class imported (which is being imported from mydependency.jar) within the MyJavaClass.class file. The stack trace for the error points to the java_import line in my_ruby_file.rb so it seems like it's not properly finding the classes imported from mydependency.jar that are included in my MyJavaClass.class file, even though it runs fine in the normal Java environment.
# contents of my_ruby_file.rb
require 'java'
require './mydependency.jar'
java_import 'MyJavaClass'
MyJavaClass.new.myJavaInstanceMethod('argument')

My $CLASSPATH environment variable was not set, which it needs to be in order for JRuby to be able to find my jar. After I ran export CLASSPATH=".:mydependency.jar" on the command line and removed the line require './mydependency.jar', it worked.

Related

spring-boot adding a custom command to actuatorshell in java

I am trying to add a java command to spring-actuator's ssh remote shell in a spring-boot applicaton. The spring-boot version is 1.2.3.RELEASE.
My sample command is just named 'kafka' and I tried placing it on the classpath in both /crash/commands as well as just /commands. It is never found - it doesn't show up in the help or actually work.
Is there some way to ask the remote shell to tell me what it's scanning/finding when it starts?
Things I have tried include specfically overriding shell.commandPathPatterns though the default seems like it should cover it.
My command - for testing - is very simple:
package commands;
#Usage("Kafka utility commands")
public class kafka extends BaseCommand {
#Command
public Object main(InvocationContext<ObjectName> context) {
return "it's all good";
}
}
After one hour of debugging I've found that the CRaSH remote shell looks for files with the extensions .groovy or .java within the packages are commands and crash.commands. The found files are compiled to bytecode, compiler errors are ignored.
I presume you use something like Maven. When you put your command into src/main/java then Maven will compile it as .class file and CRaSH will not find it. When you put your command into src/main/resources then Maven will not compile it and keep it as .java file instead.
The solution (which is quite odd for me) is to put your java command file into src/main/resources (package commands or crash.commands) so you have a .java source file in your target directory or JAR.
I tested it with spring-boot 1.2.1.RELEASE (crash.shell: 1.3.0) which should not be much different than 1.2.3.RELEASE (crash.shell: 1.3.1).

unable to execute jar file(consists dependencies), which is build from gradle

i am very new to gradle, i was trying to build a java file which is dependent on other jar file. It is building properly but when i try to execute it, it is giving "NoClassDefinitionFoundError".
my build.gradle file is:
apply plugin : 'java'
jar {
manifest {
attributes 'Main-Class': 'Hey'
}
}
dependencies
{
compile files('lib/BuildBasicJavaProject.jar') ------line A
}
if i remove the above line A then it is not even building the project.
if i keep that line A then it is building properly and producing the jar file, but when i execute it using ,
java -jar jarfilename.jar
then it is giving me a NoClassDefinitionFoundError.
Where do i need to specify the dependents path while running the jar file??
May be its a basic doubt but i wasted 2 days already in it, i tried giving
1) absolute path of the dependency file
2) adding the following line,
runtime files('lib/BuildBasicJavaProject.jar')
But did not succeed.
Thanks in advance
First welcome to Gradle world.
Your Gradle scripts seems to be correct. When you have a dependency, one jar depends on another like in your case at compile time you define compile time dependency like you did. So if you need this jar to run it you need runtime dependency, in your case. But Gradle automatically put all your compile time dependencies to be runtime dependencies. So you do not need to specify them explicitly.
So why then your code does not working?
The classpath (-cp) option is ignored if using the -jar option. So you can not specify dependent jar using -cp when type jar.So you have to write If you are on Windows
java -cp myJar.jar;.\lib\BuildBasicJavaProject.jar Hey
or use (:) and slashes(/) for Linux.
Where Hey is the full-quallified name of your main class, which have to be defind in the Manifest.
So if your class Hey is in the package:com.alabala.dev and it's name is Hey it's full qualified name is com.alabala.dev.Hey. So you have to tell Gradle
mainClassName = "com.alabala.dev.Hey"
So now Gradle put it in the manifest and when you are trying to load this jar in the JVM, she will know that to start it, she have to execute com.alabala.dev.Hey.
What is cp and why you have to specify it? Said with simple word cp is classpath - directories and archives in which JVM searches when want to load something. So here there is nothing linekd with Gradle it is Java.
You'll want to specify dependency jar(s) as a part of classpath, when you are executing your jar.
Something along these these lines:
java -cp myJar.jar:./lib/BuildBasicJavaProject.jar my.package.MyMainClass
Bare in mind that classpath delimiters are different on different platforms (: is for *nix based systems).

Opening JSON file in JRuby throws exception when evoking the Java class files generated

I use jrubyc to compile Ruby into class files. One of the Ruby files contains
dat = File.open "data.json", "r"
And there's a "data.json" file alongside. This program runs well if I directly use the jruby command.
After I compiled the Ruby files and put them into a jar, the following error appears when I run java -jar:
Exception in thread "main" org.jruby.exceptions.RaiseException: (Errno::ENOENT) data.json
at org.jruby.RubyFile.initialize(org/jruby/RubyFile.java:334)
at org.jruby.RubyIO.open(org/jruby/RubyIO.java:1144)
at RUBY.(root)(file:/Users/x5lai/Documents/rqrcode.jar!/read.rb:2)
...
To make sure that I have not put data.json in the wrong place, I have copied data.json all over the jar file, but the same error occurs.
Is there anyway to do this? Is JRuby unable to open JSON files once I have compiled the code?
I don't think that it is going to look inside the JAR by default. I created a small test and was able to reproduce your issue. I then did touch data.json and the code no longer had an error. I'm not sure how to specify that you want to look inside the JAR for your data file.

How to troubleshoot java.lang.NoSuchMethodError?

I know that a java.lang.NoSuchMethodError means that the version of a class used for compiling is different from the version used at runtime. Usually, when I see this issue, I start the app.server in java -verbose mode, which tells me the jar file from which a class is loaded. If that jar file is not the one I intended to use, I know I'm using an incorrect version of the jar file.
Another approach I use, is to use javap to look at the method signatures of the class in the jar file I am using at runtime, to confirm that the jar does indeed contain the class with a different method signature.
I am seeing this error now in Karaf, an OSGi container and none of the above approaches are helping. java -verbose shows me the jar, javap shows me the method signature and the method signature is the same as that in the error stacktrace. In other words, I can see that the class from the jar being used at runtime does have the same method signature that the jvm says it cannot find.
Here is the exact stack trace, if it helps:
java.lang.NoSuchMethodError: org.apache.axiom.om.OMXMLBuilderFactory.createSOAPModelBuilder(Ljava/io/InputStream;Ljava/lang/String;)Lorg/apache/axiom/soap/SOAPModelBuilder;
at org.apache.axis2.builder.SOAPBuilder.processDocument(SOAPBuilder.java:55)
at org.apache.axis2.transport.TransportUtils.createDocumentElement(TransportUtils.java:179)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:145)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:108)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:67)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:354)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:421)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at org.wso2.carbon.authenticator.stub.AuthenticationAdminStub.login(AuthenticationAdminStub.java:659)
Are there any other approaches I can/should use? Thanks for your help.
The Karaf commands exports [ids], imports [ids] and classes [ids] can used in combination with grep (each command has a --help option).
From the bundle throwing the error (with id N), imports N | grep org.apache.axiom.om will tell you which bundle it is actually importing that package from.
And approaching from the other side, exports | grep org.apache.axiom.om will list the bundles that export that package.
I'd expect you'll see more than one line from the exports and the import command will show incorrect version is being used.
You could also use java -verbose:class to see where classes are loaded from, which might show that the problematic class is loaded from a different bundle that you expected.

In Warbler, how do I access compiled binaries through Ruby code?

I have a piece of Ruby code which depends on a binary built from C. I generally call the binary through backticks. But now when I package the Ruby code into a jar using Warbler, I'm not sure on how I'd be able to access the binary.
My code structure looks like this:
root/
|--bin/
|--exec.rb #This is the executable when I call java -jar example.jar
|--lib/
|--Module1.rb #This dir contains all the ruby modules my code requires
|--ext/
|--a.out #A binary compiled with gcc
|--.gemspec #A file to guide warbler into building this structure into a jar
I used warble to build this entire structure into a jar. In Ruby, I can access my a.out through the following statement in exec.rb.
exec = "#{File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'ext'))}/a.out}";
`exec`
But when I try this code packaged as a jar I get the following error:
/bin/sh: file:/path/to/my/jar/example.jar!/root/ext/a.out: not found
So, how do I access the executable packaged in a jar.
Put the jar in the lib folder.
Require it in the code
require 'java'
Dir["#{File.expand_path(File.join(Rails.root, 'lib'))}/\*.jar"].each { |jar| require jar }
# A war is treated as a directory. If that is not successful add the lib folder to the CLASSPATH environment variable
Then it should be available to be used.
Edit:
Maybe this is what you are looking for https://stackoverflow.com/a/600198/643500 you can implement it with JRuby.

Resources