Taggable Add-on: A doubt with the data model in the example project

Hi,
I’m trying to use the taggable add-on in my Cuba project and I was trying to understand how it works with the aim to adapt to the requirements of the project.
I downloaded the example project from https://github.com/mariodavid/cuba-example-using-taggable.git and I don’t understand why the reference to the customer entity is saved in the attribute TAGGABLE instead of the attribute CUSTOMER_ID, created in the PersistentTagging class, like as follows:

package de.diedavids.cuba.ceut.entity;

import com.haulmont.cuba.core.entity.annotation.Extends;
import de.diedavids.cuba.taggable.entity.Tagging;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Extends(Tagging.class)
@Entity(name = "ceut$PersistentTagging")
public class PersistentTagging extends Tagging {
    private static final long serialVersionUID = 6795917365659671988L;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CUSTOMER_ID")
    protected Customer customer;

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Customer getCustomer() {
        return customer;
    }


}

As you can see on the next screen capture of the query result for database records from TAGGING table:

Why customer property is defined in PersistentTagging class, which extends from Tagging class, if it doesn’t contains the reference to the customer entity?

I’ll appreciate your help to understand this key point.
Cheers
Xavier

Hi,
I have made progress but I still have not been able to store the value of the CUSTOMER_ID attribute because now it throws an error.
I added following methods in CustomerBrowse.java for overriding those methods defined in WithTagsSupport interface: getPersistentAttribute() , getTagContext()

package de.diedavids.cuba.ceut.web.customer;

import com.haulmont.cuba.gui.components.ButtonsPanel;
import com.haulmont.cuba.gui.components.GroupTable;
import com.haulmont.cuba.gui.components.Table;
import com.haulmont.cuba.gui.screen.*;
import de.diedavids.cuba.ceut.entity.Customer;
import de.diedavids.cuba.taggable.web.WithTagsSupport;

import javax.inject.Inject;

@UiController("ceut$Customer.browse")
@UiDescriptor("customer-browse.xml")
@LookupComponent("customersTable")
@LoadDataBeforeShow
public class CustomerBrowse extends StandardLookup<Customer> implements WithTagsSupport {

    @Inject
    private GroupTable<Customer> customersTable;

    @Inject
    private ButtonsPanel buttonsPanel;

    @Override
    public Table getListComponent() {
        return customersTable;
    }

    @Override
    public ButtonsPanel getButtonsPanel() {
        return buttonsPanel;
    }

    @Override
    public boolean showTagsInList() {
        return true;
    }

    @Override
    public boolean showTagsAsLink() {
        return true;
    }
    //Methods added for defining the persistent attribute of PersistentTagging class that extends Tagging class and the context
    @Override
    public String getPersistentAttribute() {
        return "customer";
    }
    @Override
    public String getTagContext() { return "FinancialRisk";}

Now, when application is running and the user tries to add a label to a selected customer appears next error:

java.lang.UnsupportedOperationException
	at com.google.common.collect.ImmutableMap.put(ImmutableMap.java:525)
	at de.diedavids.cuba.taggable.web.action.WithTagsSupportExecutionBean.getScreenParams(WithTagsSupportExecutionBean.java:40)
	at de.diedavids.cuba.taggable.web.action.WithTagsSupportExecutionBean.openTagAssignment(WithTagsSupportExecutionBean.java:29)
	at de.diedavids.cuba.taggable.web.WithTagsSupport.lambda$initButtonWithTagsFunctionality$0(WithTagsSupport.java:125)
	at com.haulmont.bali.events.EventHub.publish(EventHub.java:170)
	at com.haulmont.cuba.gui.components.actions.BaseAction.actionPerform(BaseAction.java:222)
	at com.haulmont.cuba.web.gui.components.WebButton.buttonClicked(WebButton.java:67)
	at com.haulmont.cuba.web.widgets.CubaButton.fireClick(CubaButton.java:76)
	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 com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:83)
	at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
	at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1636)
	at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:465)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:329)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:215)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
	at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:93)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:829)

This error was located in:

@mario : Do you know if there’s something wrong in my code or it would be a bug in the Taggable Add-on?

Any help would be appreciated.
Regards

Xavier

Hi,

you are right, what it needs is the “persistentAttribute” in order to be saved in the customer column additionally.

It is normally not required to do the Tagging extension class at all. It is only needed in case you want to do joins / efficient filtering on tags. The “persistentAttribute” is like an escape path, in this case, to achieve that at all.

The idea behind the add-on, is that you actually don’t have to build up a huge data model for assigning tags. But with this simplicity, it also comes with the mentioned limitation.

But as I said, it is possible to mitigate this situation (to a certain degree) with the “persistentAttribute” field.

Regarding your question of the exception: I looks like a bug in the add-on. You can see I used ParamsMap.of(...) which in fact returns a immutable map. Doing a put operation afterwards does not look like a good idea. The reason why it works in the case of the “order” example is, that it uses the old CUBA 6 annotation based approach: cuba-example-using-taggable/OrderBrowse.groovy at master · mariodavid/cuba-example-using-taggable · GitHub. There the implementation is slightly different, therefore it works there.

The fastest thing that you can do is just to override the WithTagsSupportExecutionBean bean in your own code, copy the implementation and change line as I did in the latest commit: fix immutability bug of the params map for the UI · mariodavid/cuba-component-taggable@74806eb · GitHub

You can just register a new Spring bean under the same name and register it as an extension - see: Extending Business Logic - CUBA Platform. Developer’s Manual

Without having tested it I think it will solve the problem.

It is a little problematic to release a new version of the addon since everything is still based on bintray (which is gone) and I have not implemented a way to do that. But the above mentioned way should work.

Cheers
Mario

Thanks, Mario, for your prompt answer.

I’ll follow your detail instructions and I’m sure that the problem would be solved with your advices.

Cheers.
Xavier

Hi,

I confirm that the change in the code has worked correctly.
Thanks, @mario

Cheers
Xavier

1 Like