I am developing a javaFX 11 application that uses the javafx.scene.image class to load images from a URL:
Image(String url, boolean backgroundLoading)
where backgroundLoading is set to true.
The application works fine when run from my Eclipse IDE (using Maven). But when the application is built as a modular (JRT) application and I run the launcher to test the build, my Image objects do not load from their assigned URLs (https protocol) and instead indicate an error. The exception returned is:
java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
I have tried switching backgroundLoading to false and tried URLs from other sites that provide access to images. I have even tried changing the protocol property of the URLs from "https" to "http". Still the same outcome.
I have an ImageHandler class for handling the construction and setting of javafx.scene.image objects and another class that uses the ImageHandler to set the image of a javafx.scene.image.ImageView object (by using a listener to check when the background loading has finished).
I cannot provide the full code to reproduce the problem, but here are some snippets from the aforementioned classes:
ImageHandler - getImage():
public Image getImage() {
if (this.image == null || this.imageHadErrorLoading()) {
this.imageUrl = String.format(Settings.GATHERER_URL + ImageHandler.QUERY_DATA, this.multiverseId);
LoggerUtil.logger(this).log(Level.INFO, String.format("URL for image: %s", this.imageUrl));
try {
this.image = new Image(this.imageUrl, this.backgroundLoading);
this.setImageError(false);
} catch (Exception e) {
LoggerUtil.logger(this).log(Level.SEVERE, String.format("Exception creating new Image: %s", e.toString()));
}
}
return this.image;
}
ViewController - setCurrentImage():
private void setCurrentImage(int multiverseId) {
ImageHandler imageHandler;
imageHandler = new ImageHandler(multiverseId, true);
Image cardImage = imageHandler.getImage();
// If the image was previously loaded (successfully), just set the image.
// Otherwise, use a listener to monitor the loading of the image which
// eventually sets the image once it has successfully loaded.
if (imageHandler.imageHasLoaded()) {
this.cardImageView.setImage(cardImage);
LoggerUtil.logger(this).log(Level.INFO, String.format("Multiverse ID %d: Image cached....getting image....", multiverseId));
} else {
// This listener on the image's progress is used to set the Image View when the image has finally loaded. In the meantime,
// the Image View will continue to display the "placeholder" image.
cardImage.progressProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
double cardProgress = (double) newValue;
if (cardProgress == 1.0) {
if (cardImage.isError()) {
cardImageView.setImage(imageHandler.getErrorImage());
LoggerUtil.logger(this).log(Level.SEVERE, String.format("Multiverse ID %d: Error loading image.", multiverseId));
LoggerUtil.logger(this).log(Level.SEVERE, String.format("Image exception was: %s", cardImage.getException().getMessage()));
LoggerUtil.logger(this).log(Level.SEVERE, String.format("Image exception was: %s", cardImage.getException()));
} else {
cardImageView.setImage(cardImage);
imageHandler.setImageLoaded(true);
LoggerUtil.logger(this).log(Level.INFO, String.format("Multiverse ID %d: Image loaded successfully! Image URL: %s", multiverseId, cardImage.getUrl()));
}
}
}
});
}
Expected outcome: Application displays images when run from a built JRT module and has the same behaviour as if run from the Eclipse IDE.
Actual outcome: Application images produce SSLHandshakeException when run from a built JRT module