1 year ago

#368978

test-img

Chris Powell

Gluon Afterburner getPresenter() returns only NoSuchElementException: No value present

I generate a simple app from Gluon Start with Glisten Afterburner (v2.1.0). This generates three classes of which two are Main and AppViewManager using glisten.afterburner AppView and AppViewRegistry. I add an additional View to the generated code ("Other") and I add methods to AppViewManager to get the Presenter associated with a View.

The generated Main class looks like the following to which I have added the static calls to get Presenters: getMainPresenter() and getOtherPresenter():

public class Main extends Application {
    private final AppManager appManager = AppManager.initialize(this::postInit);

    @Override
    public void init() {
        AppViewManager.registerViewsAndDrawer();
    }

    @Override
    public void start(Stage stage) {
        appManager.start(stage);
    }

    private void postInit(Scene scene) {
    :
       // Get Main Presenter
       AppViewManager.getMainPresenter();
       // Get Other Presenter
       AppViewManager.getOtherPresenter();
    }
    :
}

AppViewManager looks like the following where I added the additional View ("Other") and added methods to get Presenters associated with Views. In registering Views, I added some output to see what is going on:

public class AppViewManager {
    private static final AppViewRegistry REGISTRY = new AppViewRegistry();

    public static final AppView MAIN_VIEW = view("Home", MainPresenter.class, MaterialDesignIcon.HOME, SHOW_IN_DRAWER, HOME_VIEW, SKIP_VIEW_STACK);
    public static final AppView OTHER_VIEW = view("Other", OtherPresenter.class, MaterialDesignIcon.NOTE, SHOW_IN_DRAWER, SKIP_VIEW_STACK);

    private static AppView view(String title, Class<?> presenterClass, MaterialDesignIcon menuIcon, AppView.Flag... flags ) {
        return REGISTRY.createView(name(presenterClass), title, presenterClass, menuIcon, flags);
    }

    private static String name(Class<?> presenterClass) {
        return presenterClass.getSimpleName().toUpperCase(Locale.ROOT).replace("PRESENTER", "");
    }

    public static void registerViewsAndDrawer()
    {
        for (AppView view : REGISTRY.getViews())
        {
            // What's in the REGISTRY?
            System.out.println("==> View: " +view.getId()+ ", Presenter: " +view.getPresenterClass().getCanonicalName());
            // Not sure what the following does, the javadoc is blank!
            view.registerView();
        }
    :
    }
    
    /**
     * Get MainPresenter.
     * See: .../AppViewRegistry.html#getPresenter(com.gluonhq.charm.glisten.afterburner.AppView)
     */
    public static void getMainPresenter()
    {
        MainPresenter mp = (MainPresenter)MAIN_VIEW.getPresenter().get();
        System.out.println("..Presenter..> " +mp.toString());
    }
    
    public static void getOtherPresenter()
    {
        OtherPresenter op = (OtherPresenter)OTHER_VIEW.getPresenter().get();
        System.out.println("..OtherPresenter..> " +op.toString());
    }
}

OtherPresenter is a simple declaration:

public class OtherPresenter {
    public void initialize() {}
}

The OtherPresenter FXML is:

<View fx:id="other" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.runtheworld.sample.OtherPresenter">
    <center>
        <VBox styleClass="box">
            <children>
                <Label text="Other!" />
            </children>
        </VBox>
    </center>
</View>

What's in the REGISTRY output is as expected (except I would have expected 'HOME_VIEW' rather than 'home'):

==> View: home, Presenter: com.runtheworld.sample.MainPresenter
==> View: OTHER_VIEW, Presenter: com.runtheworld.sample.OtherPresenter

But no matter where I make the getOtherPresenter() call, it returns: "Caused by: java.util.NoSuchElementException: No value present". The getMainPresenter() call, however, works. In fact, the app functions, showing OtherPresenter (displaying "Other!") but still throwing "No value".

Why does Main work but not Other, is there some setup/init I have missed?

Here's all the output:

==> View: home, Presenter: com.runtheworld.sample.MainPresenter
==> View: OTHER_VIEW, Presenter: com.runtheworld.sample.OtherPresenter
Apr 03, 2022 11:24:16 AM com.gluonhq.attach.util.Platform <clinit>
INFO: [Gluon Attach] System Property javafx.platform is not defined. Platform will be set to Platform.DESKTOP
..MainPresenter..> com.runtheworld.sample.MainPresenter@686bbb76
java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.get(Optional.java:143)
    at com.runtheworld.sample.AppViewManager.getOtherPresenter(AppViewManager.java:54)
    at com.runtheworld.sample.Main.postInit(Main.java:41)
    at com.gluonhq.charm.glisten.application.AppManager.continueInit(AppManager.java:328)
    at com.gluonhq.charm.glisten.application.AppManager.start(AppManager.java:288)
    at com.runtheworld.sample.Main.start(Main.java:24)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:290)
    at java.base/java.lang.Thread.run(Thread.java:833)

EDIT: I decided to eschew afterburner and simply built a View as follows:

public class OtherView {
    public static final String OTHER_VIEW = "OTHER_VIEW";
    
    public AbstractMap.SimpleEntry<String,AbstractMap.SimpleEntry<View,Presenter>> getViewController() {
        try {
            FXMLLoader f = new FXMLLoader(OtherView.class.getResource("/path/to/other.fxml"), ResourceBundle.getBundle("path.to.other"));
            View view = f.load();
            
            OtherPresenter controller = f.getController();
            return new AbstractMap.SimpleEntry(OTHER_VIEW,new AbstractMap.SimpleEntry(view,controller));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

The View and Controller are defined in the FXML and this ties the View name to the View and its associated Controller. getViewController() is called from Main.init().

gluon

nosuchelementexception

0 Answers

Your Answer

Accepted video resources