I am new to the Java world, but am familiar with Ruby. I am trying to write a program that interacts with some third-party jar files.
While the libraries seem to behave fine if called from Java, they behave incorrectly when I call them in JRuby. This is a problem because I would really like to use JRuby. For example, the two programs below try to do exactly the same thing but they produce different output:
I developed the Java program below in Netbeans and ran it by pressing F6 (Run Main Project). The Libraries folder for the project is set to "C:\Program Files (x86)\Microchip\MPLABX\mplab_ide\lib\nblibraries.properties". When I run it, it prints "pins: 17".
package pinbug1;
import com.microchip.mplab.mdbcore.assemblies.Assembly;
import com.microchip.mplab.mdbcore.assemblies.AssemblyFactory;
import com.microchip.mplab.mdbcore.simulator.PinSet;
import com.microchip.mplab.mdbcore.simulator.Simulator;
import org.openide.util.Lookup;
public class PinBug1
{
public static void main(String[] args)
{
AssemblyFactory assemblyFactory = Lookup.getDefault().lookup(AssemblyFactory.class);
Assembly assembly = assemblyFactory.Create("PIC18F14K50");
Simulator simulator = assembly.getLookup().lookup(Simulator.class);
int num = simulator.getDataStore().getProcessor().getPinSet().getNumPins();
System.out.println("pins: " + num); // prints "pins: 17"
}
}
I ran the JRuby program below by just typing jruby bug_reproduce.rb
and it printed "pins: 0". I would expect it to print "pins: 17" like the Java program.
["mplab_ide/mdbcore/modules/*.jar",
"mplab_ide/mplablibs/modules/*.jar",
"mplab_ide/mplablibs/modules/ext/*.jar",
"mplab_ide/platform/lib/org-openide-util*.jar",
"mplab_ide/mdbcore/modules/ext/org-openide-filesystems.jar"
].each do |pattern|
Dir.glob("C:/Program Files (x86)/Microchip/MPLABX/" + pattern).each do |x|
require x
end
end
assemblyFactory = org.openide.util.Lookup.getDefault.lookup(com.microchip.mplab.mdbcore.assemblies.AssemblyFactory.java_class)
assembly = assemblyFactory.create("PIC18F14K50")
simulator = assembly.getLookup.lookup(com.microchip.mplab.mdbcore.simulator.Simulator.java_class)
num = simulator.getDataStore.getProcessor.getPinSet.getNumPins
puts "pins: #{num}" # => pins: 0
There are about 80 third-party jar files. They are provided by Microchip as part of MPLAB X and implement a simulator for their microcontrollers. The jar files come with MPLAB X and I also downloaded the MPLAB X SDK to get help with using them. I am using lots of undocumented features of the libraries, but I don't see any alternative.
I am using Windows 7 64-bit SP1. I have the following Java-related things installed and listed under "Programs and Features":
I used System.getProperty("java.version")
to verify that both of my programs are running under Java 1.6.0_22. That is good, because I followed the instructions in the MPLAB X SDK that say "For best results, use the exact same JDK that built the IDE/MDBCore your code will be talking to. For MPLAB X v1.70, this is JDK 6u22 from Oracle." I only installed JDK 7u17 after I encountered this problem, and it didn't make a difference.
I was able to find a workaround to the specific problem identified in the examples, but then I continued my development and ran into another problem where the libraries behaved differently. This makes me think that I am doing something fundamentally wrong in the way I use JRuby.
Thinking that a differing class path might cause this problem, I tried getting the java program to print out its class path and then edited my JRuby program to require precisely the files in that list, but it made no difference.
Thanks to D3mon-1stVFW for actually getting MPLAB X and solving my problem for me! For those who are interested in the nitty gritty details: The number of pins was 0 because the pins are lazy loaded when they are accessed with PinSet.getPin(String). Normally all pins would have been loaded because the peripherals load them, but under JRuby no peripherals were detected. This is because the periphal document could not be found. This is because PerDocumentLocator.findDocs() returned an empty list. PerDocumentLocator failed because com.microchip.mplab.open.util.pathretrieval.PathRetrieval.getPath(com.microchip.mplab.libs.MPLABDocumentLocator.MPLABDocumentLocator.class))
was returning the wrong thing.
Consider the following code, which is similar to what is happening inside PathRetrieval.getPath (except there it was written in Java):
com.microchip.mplab.libs.MPLABDocumentLocator.MPLABDocumentLocator.java_class.resource("MPLABDocumentLocator.class").getFile()
If I follow D3mon-1stVFW's tip and add JAR files to the $CLASSPATH, then that code returns:
file:C:/Program Files (x86)/Microchip/MPLABX/mplab_ide/mplablibs/modules/com-mi crochip-mplab-libs-MPLABDocumentLocator.jar!/com/microchip/mplab/libs/MPLABDocum entLocator/MPLABDocumentLocator.class
However, if I don't add things to the class path, then that code strangely returns:
file:C:%5CProgram%20Files%20(x86)%5CMicrochip%5CMPLABX%5Cmplab_ide%5Cmplablibs% 5Cmodules%5Ccom-microchip-mplab-libs-MPLABDocumentLocator.jar!/com/microchip/mpl ab/libs/MPLABDocumentLocator/MPLABDocumentLocator.class"
The %5C is actually the code for a backslash. The Microchip code in PathRetrieval.getPath does a lot of string manipulation and does not properly handle the case where slashes are represented by %5C. If anyone has any further insight about why the %5Cs are appearing, I would be interested to know, but my problem is solved.
Conclusion: Sometimes Java's getResource() returns a URL with %5C instead of slashes in it and this is affected by what is on the CLASSPATH. If you want to be safe, add the jar file to $CLASSPATH before requiring it, like this:
require 'java'
$CLASSPATH << jar_filename
require jar_filename
I was able to get the expected results using this implementation. The main difference in this implantation is adding the jars to the classpath. If you comment this line ($CLASSPATH << jar_file
) you will get 0 pins. (Explanation in the bottom of the question)
require 'java'
Dir.glob("C:/MyCustomLibraries/MATLAB/*.jar").each do |jar_file| #Has all MPLab jars except org.netbeans.*
$CLASSPATH << jar_file
require jar_file
end
module Mplab
include_package "org.openide.util" #Lookup
include_package "com.microchip.mplab.mdbcore.simulator" #PinSet, Simulator
include_package "com.microchip.mplab.mdbcore.assemblies" #Assembly, AssemblyFactory
end
assembly_factory = Mplab::Lookup.getDefault.lookup(Mplab::AssemblyFactory.java_class)
assembly = assembly_factory.create("PIC18F14K50")
simulator = assembly.getLookup.lookup(Mplab::Simulator.java_class)
num = simulator.getDataStore.getProcessor.getPinSet.getNumPins
puts "pins: #{num}"
outputs
content/mplab/mplab.deviceSupport
content/mplab/MPHeader.xml
content/mplab/PluginBoardSupport.xml
pins: 17
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With