gluonhq / scenebuilder

Scene Builder is a visual, drag 'n' drop, layout tool for designing JavaFX application user interfaces.
https://gluonhq.com/products/scene-builder/
Other
725 stars 218 forks source link

NPE when URL value tag is used without java.net.* import #54

Open gluon-bot opened 8 years ago

gluon-bot commented 8 years ago

Originally reported by: Andre Krause (Bitbucket: akrause, GitHub: akrause)


If a tag is used within the fxml without importing the java.net.* package, a NPE is thrown if you want to open the Properties tab on the right side bar. The SB is not usable anymore after this exception.

The following NPE is thrown:

#!java

java.lang.NullPointerException
    at com.oracle.javafx.scenebuilder.kit.metadata.util.PrefixedValue.getPrefixedValueType(PrefixedValue.java:239)
    at com.oracle.javafx.scenebuilder.kit.metadata.util.PrefixedValue.<init>(PrefixedValue.java:67)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.StylesheetEditor.getType(StylesheetEditor.java:361)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.StylesheetEditor.getType(StylesheetEditor.java:348)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.StylesheetEditor.setValue(StylesheetEditor.java:158)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController.setEditorValueFromSelection(InspectorPanelController.java:1340)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController.getInitializedPropertyEditor(InspectorPanelController.java:800)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController.buildSection(InspectorPanelController.java:769)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController.buildExpandedSection(InspectorPanelController.java:692)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController.rebuild(InspectorPanelController.java:657)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController.updateInspector(InspectorPanelController.java:606)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.InspectorPanelController.editorSelectionDidChange(InspectorPanelController.java:533)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.util.AbstractPanelController.lambda$new$25(AbstractPanelController.java:231)
    at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.IntegerPropertyBase.fireValueChangedEvent(IntegerPropertyBase.java:106)
    at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
    at com.oracle.javafx.scenebuilder.kit.editor.selection.Selection.incrementRevision(Selection.java:506)
    at com.oracle.javafx.scenebuilder.kit.editor.selection.Selection.endUpdate(Selection.java:454)
    at com.oracle.javafx.scenebuilder.kit.editor.selection.Selection.select(Selection.java:370)
    at com.oracle.javafx.scenebuilder.kit.editor.selection.Selection.select(Selection.java:101)
    at com.oracle.javafx.scenebuilder.kit.editor.selection.Selection.select(Selection.java:90)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture.mouse.SelectAndMoveGesture.mousePressed(SelectAndMoveGesture.java:122)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture.mouse.AbstractMouseDragGesture.start(AbstractMouseDragGesture.java:103)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.content.mode.EditModeController.activateGesture(EditModeController.java:927)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.content.mode.EditModeController.mousePressedOnGlassLayer(EditModeController.java:702)
    at com.oracle.javafx.scenebuilder.kit.editor.panel.content.mode.EditModeController.lambda$new$12(EditModeController.java:537)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$355(GlassViewEventHandler.java:388)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)

I tested it with the attached fxml.

From Saxonia Systems.


gluon-bot commented 8 years ago

Original comment by Joeri Sykora (Bitbucket: tiainen, GitHub: tiainen):


I suggest that instead of changing the actual contents of the FXML file, that we fix this issue by showing an nice informational dialog to the user to notify that the FXML file that is being opened is invalid. We can probably first try to load the FXML file with an FXMLLoader that doesn't have static loading enabled to verify that it is a valid file, or perhaps there's another way to detect that loading the FXML fails.

We'll close the associated PR (pull request #31) now.

gluon-bot commented 8 years ago

Original comment by Andre Krause (Bitbucket: akrause, GitHub: akrause):


Yeah that is a good point Joeri. The problem for me was, where the right point is to handle this npe, so that the user doesn't recognize it and still can use the SB as intended. So the only way was for me to change the fxml to a valid document.

Because the LoadException with the invalid url is not thrown at instantiating the SB, so how could the user be informed that its fxml is invalid on startup?

So if the FXMLLoader, that already does some sort of parsing the document, doesn't find all mistakes, should there be a seperate parsing in the SB itself?

gluon-bot commented 8 years ago

Original comment by Joeri Sykora (Bitbucket: tiainen, GitHub: tiainen):


The thing is that loading the FXML file that is attached here, with FXMLLoader throws the following exception javafx.fxml.LoadException: URL is not a valid type., in other words, the FXML is actually not valid.

This is issue has a valid point though, namely the NullPointerException that is being thrown in SceneBuilder. The reason it doesn't fail with the same javafx.fxml.LoadException is because the FXMLLoader that is being used to load the FXML document has static loading enabled.

So, the thing I wanted to discuss is, what should SceneBuilder actually do:

The reason I wanted to discuss this is, is that we need to be a bit careful about just altering documents when loading them.

gluon-bot commented 8 years ago

Original comment by Andre Krause (Bitbucket: akrause, GitHub: akrause):


Saxonia Systems currently works on it.

AlmasB commented 1 year ago

@Oliver-Loeffler was this fixed in #403 ? If not, do we have an FXML that can reproduce this?

Oliver-Loeffler commented 1 year ago

Yes, #403 avoids this issue, SB remains usable and operational at attempts to load corrupted FXMLs loaded. The broken FXML is not loaded at this moment, instead an error message occurs.

Loading of FXML with incomplete or unresolvable imports is implemented with PR #576 where PR #577 presents a list of unresolvable imports to the user including a proposal how to fix this.

Anyway, I'll try to figure out a FXML to reproduce the above description.

Oliver-Loeffler commented 5 months ago

Original comment by Joeri Sykora (Bitbucket: tiainen, GitHub: tiainen):

The thing is that loading the FXML file that is attached here, with FXMLLoader throws the following exception javafx.fxml.LoadException: URL is not a valid type., in other words, the FXML is actually not valid.

This is issue has a valid point though, namely the NullPointerException that is being thrown in SceneBuilder. The reason it doesn't fail with the same javafx.fxml.LoadException is because the FXMLLoader that is being used to load the FXML document has static loading enabled.

So, the thing I wanted to discuss is, what should SceneBuilder actually do:

* try to actively alter the document to fix invalid FXML files

* or, only notify the user that the loaded FXML document contains certain warnings/errors so that he can go and fix it

The reason I wanted to discuss this is, is that we need to be a bit careful about just altering documents when loading them.

I really like the approach to first issue a notification. This means we will safely detect the issue. At the time when this works, we could think about implementing a quick fix option.

Until then, I'll see that I can prepare a suitable FXML to reproduce the error.