Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling an exception not happening on my code, what should I do?

Tags:

java

javafx

I have a JavaFX application that takes a screenshot/snapshot of a node. The code that takes the screenshot looks something like this:

WritableImage image = webView.snapshot(null, null);

where webView is a javafx.scene.web.WebView. Normally this works fine, but when the WebView is too big (and by that I mean, in the order of 10240x5548 pixels), then, I get this exception:

java.lang.NullPointerException
    at com.sun.prism.impl.ps.BaseShaderContext.initLCDBuffer(BaseShaderContext.java:703)
    at com.sun.prism.impl.ps.BaseShaderContext.validateLCDBuffer(BaseShaderContext.java:725)
    at com.sun.prism.impl.ps.BaseShaderGraphics.initLCDSampleRT(BaseShaderGraphics.java:1925)
    at com.sun.prism.impl.ps.BaseShaderGraphics.drawString(BaseShaderGraphics.java:2056)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext$10.doPaint(WCGraphicsPrismContext.java:936)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext$Composite.paint(WCGraphicsPrismContext.java:1500)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext$Composite.paint(WCGraphicsPrismContext.java:1485)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext.drawString(WCGraphicsPrismContext.java:948)
    at com.sun.webkit.graphics.GraphicsDecoder.decode(GraphicsDecoder.java:299)
    at com.sun.webkit.graphics.WCRenderQueue.decode(WCRenderQueue.java:92)
    at com.sun.webkit.WebPage.paint2GC(WebPage.java:734)
    at com.sun.webkit.WebPage.paint(WebPage.java:701)
    at com.sun.javafx.sg.prism.web.NGWebView.renderContent(NGWebView.java:96)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945)
    at com.sun.javafx.tk.quantum.QuantumToolkit$5.draw(QuantumToolkit.java:1393)
    at com.sun.javafx.tk.quantum.QuantumToolkit$5.run(QuantumToolkit.java:1429)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
    at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
    at java.lang.Thread.run(Thread.java:748)

This wouldn't be a common occurrence but I still would like to handle the situation even if only to tell the user that such resolution is not supported. The problem is that that stack trace doesn't touch my code at all. Not a single line is in my code. I guess it's a thread that's being triggered by something I call that returns immediately and later on the thread crashes.

My application is already heavily multi-threaded and thus, I have a generic error handler that looks like this:

public class ErrorHandler implements Thread.UncaughtExceptionHandler {
    public ErrorHandler(String appName) {
        super();
        // init stuff.
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        // Oh my! something went wrong.
        e.printStackTrace(); // We still want to see the exception, specially while developing.
    }
}

which I set up right after my app gets started like this:

ErrorHandler errorHandler = new ErrorHandler(APP_NAME);
Thread.setDefaultUncaughtExceptionHandler(errorHandler);

which tends to work, but for some reason, it doesn't work for that thread.

Any ideas how can I catch the situation to do something about it?

Note: I posted a related question in which I was actually getting exception reports from production in what looked like a big screenshot, but I haven't been able to trigger that exception and instead I trigger this one. That question is here: How to work around Unrecognized image loader: null in JavaFX?

Pushing harder to figure out what's going on, eventually I got this to stderr:

Outstanding resource locks detected:
D3D Vram Pool: 402,867,712 used (75.0%), 500,823,400 target (93.3%), 536,870,912 max
21 total resources being managed
average resource age is 37.2 frames
0 resources at maximum supported age (0.0%)
11 resources marked permanent (52.4%)
5 resources have had mismatched locks (23.8%)
5 resources locked (23.8%)
12 resources contain interesting data (57.1%)
0 resources disappeared (0.0%)

I'm not sure what's going on there, but it might be related.

like image 317
pupeno Avatar asked Mar 16 '18 15:03

pupeno


People also ask

How to handle exceptions in Java?

Java provides five keywords that are used to handle the exception. The following table describes each. The "try" keyword is used to specify a block where we should place an exception code. It means we can't use try block alone. The try block must be followed by either catch or finally. The "catch" block is used to handle the exception.

How do you handle exceptions in a try catch loop?

C# exception handling is done with the follow keywords: try, catch, finally, and throw. try – A try block is used to encapsulate a region of code. If any code throws an exception within that try block, the exception will be handled by the corresponding catch.

What are exceptions in C?

The Anatomy of C# Exceptions Exceptions allow an application to transfer control from one part of the code to another. When an exception is thrown, the current flow of the code is interrupted and handed back to a parent try catch block. C# exception handling is done with the follow keywords: try, catch, finally, and throw

What happens if there is an exception in the catch block?

The catch block catches the exception and statements inside the catch block is executed. If none of the statements in the try block generates an exception, the catch block is skipped. 2. Java finally block In Java, the finally block is always executed no matter whether there is an exception or not.


1 Answers

You could introduce a simple verification before performing the snapshot.

if (webView.getHeight() > 1000 || webView.getWidth() > 1000){
    throw new Exception("Web view dimension too big for capturing a snapshot!");
}
WritableImage writImage = webView.snapshot(null, null);

If you want to not hard-code the maximum values that the webView can have, you can just get the current screen bounds and compare against them.

Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
if (webView.getHeight() > primaryScreenBounds.getHeight() || webView.getWidth() > primaryScreenBounds.getWidth()){
    throw new Exception("Webview exceeds screen dimensions!");
}
like image 76
g0dzax Avatar answered Oct 17 '22 22:10

g0dzax