StandardEditor current item is null

Hi,

I have been essaying to migrate parts of a legacy application to CUBA, and find the environment and solution very promising. I am however facing a very basic problem, to which I am not being able to find good answers.

I am building complex use cases which span beyond 2 or 3 entities in depth, and the problem arises when selecting an entity from a browser and navigating to an editor to work on the topmost entity.

The point is that when I launch en editor usecase the platform throws and IllegalStateException: Current Item is null.

I simply navigate by clicking on a row in a browser screen to its primary editor screen. If I check the status of the InstanceContainer in the editor screen (at the onBeforeShow() subscribed method, the item property is null.

If I add the follwing lines in the onBeforeShow(BeforeShowEvent) method in the controller, it gets solved:

Subscribe
private void onBeforeShow(BeforeShowEvent event) {
    this.setEntityToEdit(dataManager.reload(this.getEditedEntity(), "contratoInquilino-view"));
    contratoInquilinoDc.setItem(this.getEditedEntity());

}

Basically I ask the dataManager to reload the EntityToEdit in the controller to the desired view for the screen, and then set it to the main InstanceContainer in the editor screen.

My question is, shouldn’t this piece of code be unnecessary if I already have the following annotation in the editorscreen controller?:

@EditedEntityContainer(“contratoInquilinoDc”)

I expect the platform to handle that automatically.

I have to say, I override the edit action call from the browser table by calling an utility method like this:

ScreenLaunchUtil.launchEditEntityScreen(contratoInquilinoesTable.getSingleSelected(), null, null,
            screenBuilders, this, OpenMode.NEW_TAB, null, null);

This is a utility method in a class of my own (ScreenLaunchUtil) I use to pass to the EditorBuilder 1)the entity being edited, 2) the screen id (null if primary), 3)the listcomponent (null, coming from a browser screen), 4) screenBuilders, 5) origin, 6) OpenMode, 6) dataContext (null coming from a browser screen) and 7) an AfterCloseEvent consumer which is unnecessary, so please ommit it. I attach the full code of the method at the end.

The point is that I see myself in the need of initializing the main InstanceContainer in the editor screen for it to work, when I have already supplied all the information to the platform for it to know:

. the edited entity
. the view I need in the editorscreen via de InstanceContainer
.the InstanceContainer holding the edited entity via the annotation in the controller @EditedEntityContainer(“contratoInquilinoDc”)

For the time being by @subscribing the onBeforeShow() method in the controller I can get through, and all the behavior in the editorusecase, although being complex through the subsequent InstancePropertyContainer instances down the 3 level entity depth, is working properly. So I believe I have managed to understand the expected logic of operation with the CUBA platform.

But this silly problem is driving me mad. Am I doint things right? I don’t think so. Subscribing that method is definetely a sympton that I am missing something very relevant.

Please advise. Any hints are greatly appreciated.

Here the code of my utility method:

public static <T extends StandardEntity> void launchEditEntityScreen(T e, String screenId, ListComponent listComponent, ScreenBuilders screenBuilders, FrameOwner origin, OpenMode openMode, DataContext parentDataContext, ScreenLaunchUtilCloseListener scl){
    EditorBuilder eb = screenBuilders.editor(e.getClass(), origin)
            .withLaunchMode(openMode);

    if (parentDataContext!=null){
        eb.withParentDataContext(parentDataContext);
    }
    if (screenId!=null){
        eb.withScreenId(screenId);
    }
    if (listComponent!=null){
        eb.withListComponent(listComponent);
    }
    
    eb.editEntity(e);
    Screen s = eb.build();

    s.show();

    s.addAfterCloseListener(event2->{
        StandardCloseAction ac = (StandardCloseAction) event2.getCloseAction();
        if (ac.getActionId().compareTo("commit")==0){
            if (scl!=null){
                scl.screenClosed(s);
            }

        }
        int y = 2;
    });
}

Thanks for your attention.

Carlos.

Hi,

Thank you for such a detailed description.

Certainly, it’s unnecessary.

As described in the Opening Screens doc, in order to open an editor, you need to define either editEntity(...) or newEntity(), and you certainly do:

eb.editEntity(e);

Unfortunately, without a demo project where the problem is reproduced it’s hard to say what is going wrong.

Regards,
Gleb

Hi Gleb,

thanks for your answer. What is the best way to generate this demo project. What form should it have? .war file and .sql database dump?

THanks

Carlos.

I don’t know exactly how to do it. Any quick trick?

Thanks,
Carlos.

Simply create a project that uses HSQLDB (used by default) and reproduce the problem in it. Then create a zip archive with the project using the gradle zipProject task and attach the result (an archive is created in the root directory).

Hi Gleb,

I found something important. I didn’t mention that the editorscreen contained fragments which at the time contained InstanceContainers with the same id as the EditedEntityInstanceContaine in the host screen.

I did some debugging and had the idea to see if the screen got somehow mixed up with both instancecontainers, and indeed it did. I tried removing the fragment that inherited (provided) the instancecontainer from the host screen, and voila!, it worked. I think I might be able to reproduce the mistake now that I think I got it. I don’t know if this is a bug or something simply to be aware about.

So the issue is that if instancecontainers in host and fragment screens share the same id, then the screen seems to get mixed up. However the manual says it has to be this way to work with provided containers.

What do you think?

Carlos.

There you go. Here the reproduction of my problem. If you use an editor with frangment (a-edit) you will be able to save the data, but then when opening for edition, all fields will be blank. Whereas if you keep the annotation @PrimaryEditorScreen(A.class) in the second editor, this time without fragments, it works!

Hope to hear your comments.
Any workarounds are very welcome. Have thought about creating another instance container in the host screen, giving it a different id, and then let this one be the one provided in the fragment.

I would like to keep using fragments.

Thanks for your help.
Carlos.

TestProvidedContainers.zip (86.8 KB)

sorry forgot to attach in the previous message.
Carlos.

Thank you for the demo project. I found the problem.

You’ve defined an instance container in the fragment with a loader:

<data>
    <instance id="aDc"
              class="com.company.testprovidedcontainers.entity.A"
              view="a-view" provided="true">
        <loader/>
    </instance>
</data>

But fragment doesn’t load data automatically. As documentation says:

The @LoadDataBeforeShow annotation does not work for screen fragments.

So, you need to remove the loader element from a fragment’s instance container definition:

<data>
    <instance id="aDc"
              class="com.company.testprovidedcontainers.entity.A"
              view="a-view" provided="true"/>
</data>

Regards,
Gleb

A post was split to a new topic: Jasper Report migration