Load Custom Fonts in JavaFX + Clojure - java

As background, I realize there are about 5 other posts on Stack Overflow about this, bur I've looked at the responses and researched this for countless hours with no real solution. Otherwise I wouldn't have posted here.
I'm new to JavaFX, and I like Clojure, so I'm using chrisx's clj-javafx project from Github as a Clojure wrapper for JavaFX. Most operations work great, such as placing components on the scene/stage and styling them with CSS. There's just one issue: I want to import a custom font, and so far I haven't been able to.
I've tried multiple methods. The Java version of the first thing I tried is:
Font.loadFont(<myClass>.class.getResource("mpsesb.ttf").toExternalForm(), 14);
I tried to do that in Clojure using Java interop but I'm not sure how Clojure handles Java classes. Instead I used clojure.java.io.resource:
(use '[clojure.java.io :only [resource]])
(resource "mpsesb.tff")
And it prints the URL of the .ttf file just fine.
Then I tried to use that URL and use it as a parameter in the Font.loadFont method, which didn't work. After playing around with seriously 100 permutations of dot operators and Java methods and classes, I got the following to not print any errors, unlike the other combinations I tried:
(Font/loadFont "fonts/ttf/mpsesb.ttf")
But it just returns nil, which according to the JavaFX API means the font didn't actually load. I even tried fake pathnames and they also returned nil without errors, so the Font/loadFont function seems less promising than I thought.
I finally tried using CSS to load the font instead of using Java to import it:
#font-face {
font-family: 'MyrProSemiExtBold';
src: url('file:/Users/<restOfPath>/mpsesb.ttf');
}
.label {
-fx-font-size: 14px;
-fx-font-weight: normal;
-fx-font-family: 'MyrProSemiExtBold';
}
But no luck. The labels just show up as the default font (Lucida Grande) at 14 pt.
Thank you ahead of time for any suggestions you may have.
EDIT:
Thanks, #jewelsea. The first thing I did after reading what you wrote is get Java 8 + JDK 8 (build b101). I'm using Sublime Text, so I got SublimeREPL to recognize JavaFX using Maven like so in Terminal:
$ mvn deploy:deploy-file -DgroupId=local.oracle -DartifactId=javafxrt -Dversion=8.0 -Dpackaging=jar -Dfile=/System/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/l‌​ib/ext/jfxrt.jar -Durl=file:/Users/vaniificat/.m2/repository
Most of the JavaFX-referent code worked, but now the whole javafx.scene.control package doesn't work, which means no Labels, no Buttons, no TextFields, etc.... :
> (import javafx.scene.control.Button)
: NoClassDefFoundError Could not initialize class javafx.scene.control.Button
java.lang.Class.forName0 (Class.java:-2)
> (import javafx.scene.control.Label)
: NoClassDefFoundError javafx.scene.control.Labeled
java.lang.Class.forName0 (Class.java:-2)
> (import javafx.scene.control.TextField)
: NoClassDefFoundError javafx.scene.control.Control
java.lang.Class.forName0 (Class.java:-2)
> (import '(javafx.scene.control Button Label PasswordField TextField))
: NoClassDefFoundError Could not initialize class javafx.scene.control.Button
java.lang.Class.forName0 (Class.java:-2)
A possible reference to these errors may be found at https://forums.oracle.com/thread/2526150. Basically the gist is that JavaFX 8 is only in beta so we can't expect it to work 100%. Hmm!
I opened an issue on JIRA: https://bugs.openjdk.java.net/browse/JDK-8093894. Once this gets addressed I can more fully explore #jewelsea 's other suggestions.

These are mostly suggestions rather than definitive solutions
On #font-face
Use Java 8 if you can. It has support for the #font-face css notation (which earlier versions of JavaFX such as 2.2 do not). It also has a revamped font system which might be a bit more robust. Because the font face can be loaded via css in Java 8, you may not need to solve your loading resources relative to the class location issue.
On Font.loadFont
You should be able to use the Font.loadFont method as you are trying to use it. JavaFX 2.x has supported custom fonts from it's initial release. There are some steps for loading fonts in JavaFX in plain Java: How to embed .ttf fonts is JavaFx 2.2?. I know you have already looked at that and it hasn't helped - just including it here for reference so that somebody who really knows clojure but not JavaFX may help to troublehoot the issue.
Check that your target font is compatible
Double-check that the particular font that you are using loads and is used in a regular Java based JavaFX application (just to ensure that there is not something incompatible between the font file and the JavaFX system on your platform).
You may need further help
I don't know how loading relative resources works in clojure either (or maybe there is some other issue with your code) - but perhaps a clojure expert can post another answer that allows it to work. You may want to edit your question to include an sscce.

Update: As was pointed out, the original answer did not directly answer the OP's question. I've created a blog post about the original technique in case anyone is interested.
Here is a short program that does what you want.
(ns demo.core
(:gen-class
:extends javafx.application.Application)
(:import
[javafx.application Application]
[javafx.event EventHandler]
[javafx.scene Scene]
[javafx.scene.control Button]
[javafx.scene.layout StackPane]
[javafx.scene.text Font])
(:require [clojure.java.io :as jio]))
(defn- get-font-from-resource
"Load the named font from a resource."
[font-name]
(let [prefix "demo/resources/"
url (jio/resource (str prefix font-name))
fnt (Font/loadFont (.toExternalForm url) 20.0)]
fnt))
(defn -start
"Build the application interface and start it up."
[this stage]
(let [root (StackPane.)
scene (Scene. root 600 400)
fnt (get-font-from-resource "ITCBLKAD.TTF")
btn (Button. "Press Me!")]
(.setOnAction btn
(reify EventHandler
(handle [this event]
(doto btn
(.setText (str "This is " (.getName fnt)))
(.setFont fnt)))))
(.add (.getChildren root) btn)
(doto stage
(.setTitle "Font Loading Demo")
(.setScene scene)
(.show))))
(defn -main
[& args]
(Application/launch demo.core args))
In this project, I placed the font file in resources, a sub-directory of demo - where the Clojure source is stored - hence the "prefix" in the function get-font-from-resource.
It looks like the problem you might have been having with loadFont was in your conversion from the URL to the String form. The external form is an absolute path starting at the root directory on the drive.
Tip: You probably know this, but one thing that continually screws me up are methods in JavaFX that require double parameters, like Font/loadFont. I'm used to Java just promoting integer arguments to double. In Clojure, if you use an integer where a double is required, the program fails with a less than useful error message.

Related

Why does java.awt.Font.getStringBounds give different result on different machines?

I have an application that generates PDF reports (using JasperReports), however if I run my application on my development laptop the text fields have a slightly different size than when I generate the exact same report on the server. I eventually reduced the issue to the following code:
final Font font = Font.createFont(
Font.TRUETYPE_FONT,
MyTest.class.getResourceAsStream("/fonts/europa/Europa-Bold.otf")
).deriveFont(10f);
System.out.println(font);
System.out.println(font.getStringBounds(
"Text",
0,
4,
new FontRenderContext(null, true, true)
));
On my Laptop this prints:
java.awt.Font[family=Europa-Bold,name=Europa-Bold,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-9.90999,w=20.080002,h=12.669988]
On the server this prints:
java.awt.Font[family=Europa-Bold,name=Europa-Bold,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-7.6757812,w=20.06897,h=10.094452]
As you can see I actually ship the font file with the application, so I believe that there is no chance that both machines actually work with a different font.
I would have guessed that under these conditions the output of getStringBounds is system-independent. Obviously it is not. What could possibly cause the difference?
Disclaimer! : I'm not a font dev expert, just sharing my experience.
Yes, it's kind of native. Even new JavaFX web view for example, is depends on webkit.
If you dive into debugging for getStringBounds, you will realize it reaches a point, where font manager should decide to load a concreted font manager, where the class name is supposed to be system property sun.font.fontmanager.
Source code of sun.font.FontManagerFactory
...
private static final String DEFAULT_CLASS;
static {
if (FontUtilities.isWindows) {
DEFAULT_CLASS = "sun.awt.Win32FontManager";
} else if (FontUtilities.isMacOSX) {
DEFAULT_CLASS = "sun.font.CFontManager";
} else {
DEFAULT_CLASS = "sun.awt.X11FontManager";
}
}
...
public static synchronized FontManager getInstance() {
...
String fmClassName = System.getProperty("sun.font.fontmanager", DEFAULT_CLASS);
}
Those DEFAULT_CLASS values could validate your Obviously it is not. What could possibly cause the difference? mark.
The val for sun.font.fontmanager may be sun.awt.X11FontManager for some nix systems, but could be null for windows for instance, so the manager will be sun.awt.Win32FontManager.
Now each manager, may depends on vary underlying shaping/rendering engine/impl for sure(this may help).
Main reason could be the nature of fonts. As they are mostly vector stuffs. So based on platform/env, a rendered text could be bigger, or smaller. e.g., maybe windows apply desktop cleartype, and screen text size(DPI) on requested text rendering.
It seems, even if you have exactly two sun.awt.X11FontManager manager, the results will be vary. this may help too
If you just try out the sample code, on online compilers, you will face with vary results for sure.
Result of ideaone (https://ideone.com/AuQvMV), could not be happened, stderr has some interesting info
java.lang.UnsatisfiedLinkError: /opt/jdk/lib/libfontmanager.so: libfreetype.so.6: cannot open shared object file: No such file or directory
at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2430)
at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2487)
at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2638)
at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:827)
at java.base/java.lang.System.loadLibrary(System.java:1902)
at java.desktop/sun.font.FontManagerNativeLibrary$1.run(FontManagerNativeLibrary.java:57)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:310)
at java.desktop/sun.font.FontManagerNativeLibrary.<clinit>(FontManagerNativeLibrary.java:32)
at java.desktop/sun.font.SunFontManager$1.run(SunFontManager.java:270)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:310)
at java.desktop/sun.font.SunFontManager.<clinit>(SunFontManager.java:266)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:415)
at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:82)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:310)
at java.desktop/sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
at java.desktop/java.awt.Font.getFont2D(Font.java:497)
at java.desktop/java.awt.Font.getFamily(Font.java:1410)
at java.desktop/java.awt.Font.getFamily_NoClientCode(Font.java:1384)
at java.desktop/java.awt.Font.getFamily(Font.java:1376)
at java.desktop/java.awt.Font.toString(Font.java:1869)
at java.base/java.lang.String.valueOf(String.java:3042)
at java.base/java.io.PrintStream.println(PrintStream.java:897)
at Ideone.main(Main.java:19)
Note the failed/missed load of libfreetype which is a native/C font rendering app
Result of coding ground (https://www.tutorialspoint.com/compile_java_online.php)
fnt manager: sun.awt.X11FontManager
java.awt.Font[family=Dialog,name=tahoma,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-9.282227,w=22.09961,h=11.640625]
Result of jdoodle (https://www.jdoodle.com/online-java-compiler/)
fnt manager: sun.awt.X11FontManager
java.awt.Font[family=Dialog,name=tahoma,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-9.839991,w=24.0,h=12.569988]
My machine
fnt manager: null
java.awt.Font[family=Tahoma,name=tahoma,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-10.004883,w=19.399414,h=12.0703125]
My Story (may help, you may try)
I had similar issue back in some years ago, where text rendering using exactly same embedded font failed on macOs/jdk8, for complex text rendering(lots of ligatures). Not just sizes, but also broken ligatures, kerning, etc...
I could fix my issue(cannot remember if fixed the sizing, but no broken ligatures for sure), using another workground, as following
InputStream is = Main.class.getResourceAsStream(fontFile);
Font newFont = Font.createFont(Font.TRUETYPE_FONT, is);
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(newFont);
//later load the font by constructing a Font ins
Font f = new Font(name/*name of the embedded font*/, style, size);
Registering font using GraphicsEnvironment, and then instancing it using Font fixed our issue. So you may also give it a try.
Solution
Finally, I just step-down the jdk stuffs(it's really great pain in neck) for good, and came up with harfbuzz(shaping) + freetype(rendering) native impl that indeed was a peace in mind.
So...
• You may consider your production server(easy way) as reference for rendered font advance and rendering, and validate the result based on it(rather than dev machine)
• Or, use a cross and standalone (and probably native) shaping/rendering font engine/impl to make sure dev and production results will be the same.

Wicket: rendering HTML5 audio from plain string

I'd like to render HTML5 audio using Apache Wicket.
I am trying to render it from plain string. I know it's probably not the best way to do this so first I'd like to ask: is it even possible without getting errors?
Here's what I'm doing:
JAVA:
String html5AudioStr = "<audio controls><source src=\"test.mp3\" type=\"audio/mpeg\">Your browser does not support the audio element.</audio>";
add(new Label("html5Audio", html5AudioStr).setEscapeModelStrings(false));
HTML:
<span wicket:id="html5Audio"></span>
By doing this, I can see the audio player and the <audio> tag is rendered correctly. But I'm getting this error:
java.lang.ClassNotFoundException: test.mp3
And the file has this URL:
http://localhost:8080/wicket/bookmarkable/test.mp3
instead of:
http://localhost:8080/test.mp3
Is there anything I could do to fix it?
You use relative path for source. That's why browser is trying resolve absolute path relative to your page (seems it's located in /wicket/bookmarkable/).
If you are going to use / context you can simply add "/" before "test.mp3" - it should be "/test.mp3".
But if you are going to mount your application to other place rather then root context "/", I recommend to take a look to 'ContextRelativeResource'.
As of Wicket 7 media tags (audio, video, track, source) are now part of the core API.
Documentation:
Wicket User Guide 7.x - 16.3 Package resources
"Media tags - resource references with content range support"
Javadoc:
https://ci.apache.org/projects/wicket/apidocs/7.x/index.html - Packages:
org.apache.wicket.markup.html.media
org.apache.wicket.markup.html.media.audio
org.apache.wicket.markup.html.media.video
There are also some additional implementations in the "html5" module of WicketStuff about Subtitles and WebRTC.
https://github.com/wicketstuff/core/wiki/Html5

UIDefaults.getUI() failed: error when loading a JFrame into another project

I found this project which works just fine in a standalone run. However when I try to add it to a JPanel in another project (already did this in the exact same project but with a JFrame of my own and worked fine) this error arises:
UIDefaults.getUI() failed: no ComponentUI class for: doubleslider.MThumbSlider[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=,isInverted=false,majorTickSpacing=0,minorTickSpacing=0,orientation=HORIZONTAL,paintLabels=false,paintTicks=false,paintTrack=true,snapToTicks=false,snapToValue=true]
java.lang.Error
at javax.swing.UIDefaults.getUIError(UIDefaults.java:729)
at javax.swing.MultiUIDefaults.getUIError(MultiUIDefaults.java:130)
at javax.swing.UIDefaults.getUI(UIDefaults.java:759)
at javax.swing.UIManager.getUI(UIManager.java:1002)
at javax.swing.JSlider.updateUI(JSlider.java:323)
at doubleslider.MThumbSlider.updateUI(MThumbSlider.java:44)
at javax.swing.JSlider.<init>(JSlider.java:275)
at javax.swing.JSlider.<init>(JSlider.java:182)
at doubleslider.MThumbSlider.<init>(MThumbSlider.java:24)
at doubleslider.DoubleSlider.<init>(DoubleSlider.java:29)
at com.einge.scadaremotecontrol.Ventana.<init>(Ventana.java:227)
at com.einge.scadaremotecontrol.ScadaRemoteControl.<init>(ScadaRemoteControl.java:92)
at com.einge.scadaremotecontrol.ScadaRemoteControl.main(ScadaRemoteControl.java:197)
UIDefaults.getUI() failed: no ComponentUI class for: doubleslider.MThumbSlider[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=,isInverted=false,majorTickSpacing=0,minorTickSpacing=0,orientation=HORIZONTAL,paintLabels=false,paintTicks=false,paintTrack=true,snapToTicks=false,snapToValue=true]
java.lang.Error
at javax.swing.UIDefaults.getUIError(UIDefaults.java:729)
at javax.swing.MultiUIDefaults.getUIError(MultiUIDefaults.java:130)
at javax.swing.UIDefaults.getUI(UIDefaults.java:759)
at javax.swing.UIManager.getUI(UIManager.java:1002)
at javax.swing.JSlider.updateUI(JSlider.java:323)
at doubleslider.MThumbSlider.updateUI(MThumbSlider.java:44)
at doubleslider.MThumbSlider.<init>(MThumbSlider.java:26)
at doubleslider.DoubleSlider.<init>(DoubleSlider.java:29)
at com.einge.scadaremotecontrol.Ventana.<init>(Ventana.java:227)
at com.einge.scadaremotecontrol.ScadaRemoteControl.<init>(ScadaRemoteControl.java:92)
at com.einge.scadaremotecontrol.ScadaRemoteControl.main(ScadaRemoteControl.java:197)
My first guess is that the MultiTumbSlider class is trying to set a different Look&Feel than my JFrame. Any solutions? I couldn't figure this out and I really need two sliders so to have a time Range
Any help will be appretiated!
I don't recognize the loading approach used in this very old example; it appear to be based on the current Look & Feel. You might try setting javax.swing.plaf.metal.MetalLookAndFeel explicitly. Going forward, look at Kirill Grouchnikov's How to Write a Custom Swing Component for guidance on modernizing the delegate plumbing.
At the book "Java Swing, 2nd Edition", by Marc Loy et. al., at the section "Creating Your Own Component" (Chapter 28: Swing Under the Hood), we have the code line at the main() method:
UIManager.put(JogShuttleUI.UI_CLASS_ID, "BasicJogShuttleUI");
This will inform the UIDefaults, through UIManeger, the class name of the basic UI delegate of the custom component. Note, however, that you must provide the fully qualified class name, since it will be located by the class loading mechanism.
For example, when I'm use
UIManager.put(DiagramUI.UI_CLASS_ID, "BasicDiagramUI");
I get the same error reported by your question. But, when I change it to
UIManager.put(DiagramUI.UI_CLASS_ID, BasicDiagramUI.class.getName());
Things works pretty well. Nice coding!

Using Inline::Java in perl with threads

I am writing a trading program in perl with the newest Finance::InteractiveBrokers::TWS
module. I kick off a command line interface in a separate thread at the
beginning of my program but then when I try to create a tws object, my program
exits with this message:
As of Inline v0.30, use of the Inline::Config module is no longer supported or
allowed. If Inline::Config exists on your system, it can be removed. See the
Inline documentation for information on how to configure Inline. (You should
find it much more straightforward than Inline::Config :-)
I have the newest versions of Inline and Inline::Java. I looked at TWS.pm and it doesn't seem to be using Inline::Config. I set 'SHARED_JVM => 1' in the 'use Inline()' and 'Inline->bind()' calls in TWS.pm but that did not resolve the issue...
My Code:
use Finance::InteractiveBrokers::TWS;
use threads;
use threads::shared;
our $callback;
our $tws;
my $interface = UserInterface->new();
share($interface);
my $t = threads->create(sub{$interface->runUI()});
$callback= TWScallback->new();
$tws = Finance::InteractiveBrokers::TWS->new($manager); #This is where the program fails
So is Inline::Config installed on your system or not? A cursory inspection of the code is not sufficient to tell whether Perl is loading a module or not. There are too many esoteric ways (some intentional and some otherwise) to load a package or otherwise populate a namespace.
The error message in question comes from this line of code in Inline.pm:
croak M14_usage_Config() if %main::Inline::Config::;
so something in your program is populating the Inline::Config namespace. You should do what the program instructs you to do: find out where Inline/Config.pm is installed on your system (somewhere in your #INC path) and delete it.

Problems Calling a Java Class from JRuby

I'm trying to use boilerpipe from JRuby. I've seen the guide for calling Java from JRuby, and have used it successfully with another Java package, but can't figure out why the same thing isn't working with boilerpipe.
I'm trying to basically do the equivalent of this Java from JRuby:
URL url = new URL("http://www.example.com/some-location/index.html");
String text = ArticleExtractor.INSTANCE.getText(url);
Tried this in JRuby:
require 'java'
url = java.net.URL.new("http://www.example.com/some-location/index.html")
text = Java::DeL3sBoilerpipeExtractors::ArticleExtractor.INSTANCE.getText(url)
This is based on the API Javadocs for boilerpipe. Here's the error:
jruby-1.6.0 :042 > Java::DeL3sBoilerpipeExtractors::ArticleExtractor
NameError: cannot load Java class deL3sBoilerpipeExtractors.ArticleExtractor
from org/jruby/javasupport/JavaClass.java:1195:in `for_name'
from org/jruby/javasupport/JavaUtilities.java:34:in `get_proxy_class'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/site_ruby/shared/builtin/javasupport/java.rb:45:in `const_missing'
from (irb):42:in `evaluate'
from org/jruby/RubyKernel.java:1087:in `eval'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/1.8/irb.rb:158:in `eval_input'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/1.8/irb.rb:271:in `signal_status'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/1.8/irb.rb:270:in `signal_status'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/1.8/irb.rb:155:in `eval_input'
from org/jruby/RubyKernel.java:1417:in `loop'
from org/jruby/RubyKernel.java:1190:in `catch'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/1.8/irb.rb:154:in `eval_input'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/1.8/irb.rb:71:in `start'
from org/jruby/RubyKernel.java:1190:in `catch'
from /usr/local/rvm/rubies/jruby-1.6.0/lib/ruby/1.8/irb.rb:70:in `start'
from /usr/local/rvm/rubies/jruby-1.6.0/bin/irb:17:in `(root)'
Looks like it didn't parse the camelcase into the appropriate Java package name. What am I doing wrong? I believe I've set up my classpath alright (last 3 entries), though there may be some conflict with xerces possibly being included twice:
$ echo $CLASSPATH
:/jellly/Maui1.2:/jellly/Maui1.2/src:/jellly/Maui1.2/bin:/jellly/Maui1.2/lib/commons-io-1.4.jar:/jellly/Maui1.2/lib/commons-logging.jar:/jellly/Maui1.2/lib/icu4j_3_4.jar:/jellly/Maui1.2/lib/iri.jar:/jellly/Maui1.2/lib/jena.jar:/jellly/Maui1.2/lib/maxent-2.4.0.jar:/jellly/Maui1.2/lib/mysql-connector-java-3.1.13-bin.jar:/jellly/Maui1.2/lib/opennlp-tools-1.3.0.jar:/jellly/Maui1.2/lib/snowball.jar:/jellly/Maui1.2/lib/trove.jar:/jellly/Maui1.2/lib/weka.jar:/jellly/Maui1.2/lib/wikipediaminer1.1.jar:/jellly/Maui1.2/lib/xercesImpl.jar:/jellly/boilerpipe-1.1.0/boilerpipe-1.1.0.jar:/jellly/boilerpipe-1.1.0/lib/nekohtml-1.9.13.jar:/jellly/boilerpipe-1.1.0/lib/xerces-2.9.1.jar
I'd recommend against trying to guess the module name we put under Java::, since for unusual packages it can get mangled pretty badly. Use java_import 'your.weird.package.ArticleExtractor' or if all the package components are compatible with Ruby method naming, you can also do Java::your.weird.package.ArticleExtractor.
Also, since you might run into this... you'll want to reference the INSTANCE variable as ArticleExtractor::INSTANCE, since we map it as a Ruby constant.
Have fun!
You can also use the nice Jruby Boilerpipe Gem which wraps the Java code
Or the pure ruby implementation of Boilerpipe Ruby Boilerpipe Gem
require 'boilerpipe'
Boilerpipe::Extractors::ArticleExtractor.text("https://github.com/jruby/jruby/wiki/AboutJRuby")

Categories