InvalidStateException on getter for MxN relation

I am experiencing an InvalidStateException on the getter for a Set<> which is a MxN relation between two entities. As shown below:

java.lang.IllegalStateException: Cannot get unfetched attribute [doiFpms] from detached object com.calidus.pdcs.entity.documents.DocItem-03f8a4b8-cbf8-e2a8-8a5c-66406460ca4d [detached].
	at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.throwUnfetchedAttributeException(UnitOfWorkValueHolder.java:326)
	at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:106)
	at org.eclipse.persistence.indirection.IndirectSet.buildDelegate(IndirectSet.java:227)
	at org.eclipse.persistence.indirection.IndirectSet.getDelegate(IndirectSet.java:438)
	at org.eclipse.persistence.indirection.IndirectSet.size(IndirectSet.java:626)
	at java.base/java.util.HashSet.<init>(HashSet.java:119)
	at com.calidus.pdcs.entity.documents.DocItemHelper.deepCopyDocItem(DocItemHelper.java:20)
	at com.calidus.pdcs.entity.documents.DocVersionHelper.deepCopyDocVersion(DocVersionHelper.java:187)
	at com.calidus.pdcs.screen.docversion.DocVersionBrowse.onDocVersionsTableDuplicateDov(DocVersionBrowse.java:240)
	at io.jmix.core.common.event.EventHub.publish(EventHub.java:170)
	at io.jmix.ui.action.BaseAction.actionPerform(BaseAction.java:220)
	at io.jmix.ui.component.impl.ButtonImpl.buttonClicked(ButtonImpl.java:75)
	at io.jmix.ui.widget.JmixButton.fireClick(JmixButton.java:77)
	at com.vaadin.ui.Button$1.click(Button.java:57)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:153)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:115)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:442)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:407)
	at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:275)
	at 
.
.
.

The relationship is a MxN between DocItem and FTIParameter, as follows:
image

The entities declaration contains:

DocVersion:

    @Comment("Document items for this document version.")
    @OrderBy("doiOrder")
    @Composition
    @OneToMany(mappedBy = "doiDov", cascade = CascadeType.ALL)
    private List<DocItem> dovDois = new ArrayList<>();

DocItem:

    @Comment("Instrumentation parameters")
    @JoinTable(name = "DOC_ITEM_FTI_PARAMETER_LINK",
            joinColumns = @JoinColumn(name = "DOC_ITEM_ID", referencedColumnName = "ID"),
            inverseJoinColumns = @JoinColumn(name = "FTI_PARAMETER_ID", referencedColumnName = "ID"))
    @ManyToMany
    private Set<FtiParameter> doiFpms;

FTIParameter:

    @Comment("Referencer document items")
    @JoinTable(name = "DOC_ITEM_FTI_PARAMETER_LINK",
            joinColumns = @JoinColumn(name = "FTI_PARAMETER_ID"),
            inverseJoinColumns = @JoinColumn(name = "DOC_ITEM_ID"))
    @ManyToMany
    private Set<DocItem> fpmDois;

I can populate the relationship on the editor screen fragment for DocItem relating to various FTIParameters, as shown below:
image
image

The code where the exception is occurring is the implementation of an action to copy an instance of DocItem in the DocVersion browser screen. I have the ordinary collection container for browsing DocVersion instances (DocVersionsDc) and an additional InstanceContainer with a “heavier” fetch plan (DocVersionDc) which I use to fetch all fields that allow me to duplicate the currently selected DocVersion instance and all related DocItem entities when a “duplicate” action is called by the user:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://jmix.io/schema/ui/window"
        xmlns:c="http://jmix.io/schema/ui/jpql-condition"
        caption="msg://docVersionBrowse.caption"
        focusComponent="docVersionsTable">
    <data readOnly="true">
        <collection id="docVersionsDc"
                    class="com.calidus.pdcs.entity.documents.DocVersion">
            <fetchPlan extends="_base">
                <property name="dovDoc" fetchPlan="_base"/>
            </fetchPlan>
            <loader id="docVersionsDl"/>
        </collection>
        <instance id="docVersionDc"
                  class="com.calidus.pdcs.entity.documents.DocVersion">
            <fetchPlan extends="_base">
                <property name="dovDoc" fetchPlan="_base"/>
                <property name="dovDois" fetchPlan="_base">
                    <property name="doiFpms" fetchPlan="_base"/>
                    <property name="doiTkd" fetchPlan="_base">
                        <property name="tkdTcss" fetchPlan="_base">
                            <property name="tcsTacs" fetchPlan="_base">
                                <property name="tacCdv" fetchPlan="_base"/>
                            </property>
                        </property>
                    </property>
                </property>
            </fetchPlan>
            <loader id="docVersionDl"/>
        </instance>
    </data>

The load delegate for the instance container is:

    @Install(to = "docVersionDl", target = Target.DATA_LOADER)
    private DocVersion docVersionDlLoadDelegate(final LoadContext<DocVersion> loadContext) {
        DocVersion dov = this.docVersionsTable.getSingleSelected();
        if (dov == null){
            return null;
        }
        return dataManager.load(DocVersion.class)
                .query("select dov from DocVersion dov" +
                                " join dov.dovDoc doc " +
                                " join dov.dovDois doi " +
                                " left join doi.doiFpms fpm " +
                                " left join doi.doiTkd tkd " +
                                " left join tkd.tkdTcss tcs " +
                                " left join tcs.tcsTacs tac " +
                                " join tac.tacCdv cdv " +
                                " where dov=:dovp")
                .parameter("dovp", this.docVersionsTable.getSingleSelected())
                .one();
    }

The code where the exception occurs is a “duplicate instance” function within a helper class for DocItem. The exception occurs on the getter for the “doiFpms” attribute:

    public static DocItem deepCopyDocItem(DocItem docItem, MetadataTools metadataTools){
        // Returns a copy of a document item and all linked entities
        DocItem doiOut = metadataTools.copy(docItem);
        .
        .
        .
        if (docItem.getDoiFpms() != null){
            doiOut.setDoiFpms(new HashSet<>(docItem.getDoiFpms()));
        }
        return doiOut;
    }

I remember having a similar problem before and it generally occurs when I have a fetch plan traversing more than one level of relationships. In this case DocVersion -> getDovDois() -> getDoiFpms(). May that be the cause of the problem?

Jmix version: 1.5.5
Jmix Studio plugin version: 2.1.3-231
IntelliJ version: IntelliJ IDEA 2023.1.5 (Community Edition)

java 11.0.10 2021-01-19 LTS
Java™ SE Runtime Environment 18.9 (build 11.0.10+8-LTS-162)
Java HotSpot™ 64-Bit Server VM 18.9 (build 11.0.10+8-LTS-162, mixed mode)

I will withdraw this question because I just discovered other problems in my code and my changes led me in another direction.
Please disregard it.

1 Like