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)
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.
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.