Specific collection validation

Hi all,
I’m trying to implement a specific collection validation.
This is the use case;

  1. entity Artist pays every year a Membership fee to be associated to organization
  2. she/he pays a first time association fee and next 5 years yearly-fee
  3. every year she/he have to pay within a certain date starting from year beginning

these are my requirements.
Entities: ArtistInfo and MembershipFee 1 to many composition (with type an enumeration which classify Fee type, first year or following years).

When creating new Fee I have to examine collection to validate insertion of new fee.
From ArtistInfo Editor I pass ad parameter ArtistInfo Entity to MembershipFee Editor but Membership Fees collection is empty (due to Lazy.Loading?):
So I have to hit database to get MembershipFee.
Validation is implemented in Editor postValidate() method to report internationalized messages in the standard way (adding errors messages). It is implemented applying different groovy closures to MembershipFee collection.

To collect MembershipFees first I tryed with collectionDatasource, than I found datasource are better suited for editing/visualizing, so I tried JPQL query in DataManager and at the end I implemented a specific service (excessive only to get related entities in my opinion)

I get this error (head part):

java.lang.IllegalArgumentException: MetaClass not found for contactsclass
	at com.haulmont.cuba.core.sys.CachingMetadataSession.getClassNN(CachingMetadataSession.java:70)
	at com.haulmont.cuba.core.sys.MetadataImpl.getClassNN(MetadataImpl.java:319)
	at com.haulmont.cuba.core.sys.PersistenceSecurityImpl.applyConstraints(PersistenceSecurityImpl.java:75)
	at sun.reflect.GeneratedMethodAccessor170.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:84)
	at com.haulmont.cuba.core.sys.PerformanceLogInterceptor.aroundInvoke(PerformanceLogInterceptor.java:29)
	at sun.reflect.GeneratedMethodAccessor169.invoke(Unknown Source)

Similar in service.

Can I simply force reload of collection of related objects?

---------------------------- Editor code --------------------------------------------------------------------------

package pro.sysonline.contacts.web.membershipfee

import com.haulmont.cuba.core.global.DataManager
import com.haulmont.cuba.core.global.LoadContext
import com.haulmont.cuba.core.global.Messages
import com.haulmont.cuba.gui.components.AbstractEditor
import com.haulmont.cuba.gui.components.ValidationErrors
import groovy.transform.CompileStatic
import pro.sysonline.contacts.entity.ArtistInfo
import pro.sysonline.contacts.entity.MembershipFee
import pro.sysonline.contacts.entity.MembershipFeeType
import pro.sysonline.contacts.service.MembershipFeeService

import javax.inject.Inject

@CompileStatic
class MembershipFeeEdit extends AbstractEditor<MembershipFee> {

    private ArtistInfo a

    @Inject
    private DataManager dataManager

    @Inject
    private Messages messages

   @Inject
    private MembershipFeeService memberShipService

    /*@Inject
    protected Metadata metadata
*/

    @Override
    void init(Map<String, Object> params) {
        super.init(params)
        a = (ArtistInfo) params.get("artist")
    }

    // Initialize Editor for new MembershipFee Item
    @Override
    protected void initNewItem(MembershipFee item) {
        item.artistInfo = a
    }

    @Override
    void postValidate(ValidationErrors errors) {
        Integer MAX_YEARLY_FEE = 5
        MembershipFee it
        List<MembershipFee> l = new ArrayList<MembershipFee>()
        l = loadMembershipFees(a)

        if ((l != null) && (!l.isEmpty())) {

            // First Year already present
            if (item.type.equals(MembershipFeeType.FIRST_YEAR))
                if (l.any() { it.type == MembershipFeeType.FIRST_YEAR })
                    errors.add(messages.getMessage(getClass(), "errorFY"))

            // All Fees presents
            if (l.count() { it.type == MembershipFeeType.NEXT_YEAR } == MAX_YEARLY_FEE)
                errors.add(messages.getMessage(getClass(), "errorMAX_YF"))

        }
    }

    private List<MembershipFee> loadMembershipFees(ArtistInfo a) {

    /*    Session session = metadata.getSession()
        MetaClass metaClass1 = session.getClassNN("contacts$MembershipFee")*/

        /*LoadContext<MembershipFee> loadContext = LoadContext.create(MembershipFee.class)
                .setQuery(LoadContext.createQuery("select f from contacts$MembershipFee f where f.artistInfo.id = :artistId")
                .setParameter("artistId", a.id))
                .setView("membershipFee-basic")*/
        //return dataManager.loadList(loadContext)

        return memberShipService.getMemberShipFeesForArtist(a)

        // Temporary Workaround
        //return null

    }

}

---------------------------- Service code --------------------------------------------------------------------------

package pro.sysonline.contacts.service

import com.haulmont.cuba.core.EntityManager
import com.haulmont.cuba.core.Persistence
import com.haulmont.cuba.core.Transaction
import org.slf4j.Logger
import org.springframework.stereotype.Service
import pro.sysonline.contacts.entity.ArtistInfo
import pro.sysonline.contacts.entity.MembershipFee

import javax.inject.Inject

@Service(MembershipFeeService.NAME)
public class MembershipFeeServiceBean implements MembershipFeeService {

    @Inject
    Logger log

    @Inject
    private Persistence persistence




    @Override
    List<MembershipFee> getMemberShipFeesForArtist(ArtistInfo a) {
        EntityManager em = null
        Transaction tx = null
        com.haulmont.cuba.core.Query query = null
        List<MembershipFee>  l
        String queryStr = "select f from contacts$MembershipFee f where f.artistInfo = :artistId"

        try {

            tx = persistence.createTransaction()
            em = persistence.getEntityManager()

            query = em.createQuery(queryStr)
            query.setParameter("artistId",a.id)
q
            l = (List<MembershipFee>) query.getResultList()

            tx.commit()

        } catch (Exception ex) {
            log.debug(Class.getName())
        } finally {
            tx.end()
        }


        return ((null != l)  ? l : new ArrayList<MembershipFee>())
    }
}

Thank you in advance for your advice.

Fabrizio

Hi Fabrizio,

It would be very helpful if you attached a small sample project with a minimal amount of entities (only those mentioned in your question) and the MembershipFeeService, thus we’ll be able to help you.

Thank you, I’ll do it

Sorry for being so late. I tried Datamanager in a different editor controller code written in Groovy. Same error, but I think it is due to Groovy which has some classes which overolads Datamanager ones and are called automatically via reflection or similar mechanism, so import is ineffective (the idea I made of it) . All Datamanager Examples in documentation are written in Java. Some code (that is similar to previous one).

Observe this:
import com.haulmont.chile.core.model.MetaClass <<<< Greyed in Intellij IDEA

in Grrovy Package groovy.lang

Code follows.

Some one had similar experience?

Thanks in advance.

---->>> Controller: invoiceEdit.groovy

package pro.sysonline.contacts.web.invoice
import com.haulmont.cuba.core.entity.Entity
import com.haulmont.cuba.core.global.DataManager
import com.haulmont.cuba.core.global.LoadContext
import com.haulmont.cuba.core.global.Messages
import com.haulmont.chile.core.model.MetaClass    <<<< Greyed in Intellij IDEA
import com.haulmont.cuba.gui.components.*
import com.haulmont.cuba.gui.components.actions.RemoveAction
import com.haulmont.cuba.gui.data.CollectionDatasource
import com.haulmont.cuba.gui.data.Datasource
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory
import pro.sysonline.contacts.entity.*
import pro.sysonline.contacts.service.InvoiceNrService

VatTable is a simple entity POJO in Java so no code here

// Code ------

String query_str = "select v from contacts$VatTable v where enabled=true order by v.description asc"
        LoadContext<VatTable> loadContext = LoadContext.create(VatTable.class)
                .setQuery(LoadContext.createQuery(query_str))
                //.setParameter("enabled", true))
                //.setView("VatTable.full"))
        List<VatTable> vat_tbl = dataManager.loadList(loadContext)

eventually (with quite useless parameter):

String query_str = "select v from contacts$VatTable v where enabled=:enabled order by v.description asc"
        LoadContext<VatTable> loadContext = LoadContext.create(VatTable.class)
                .setQuery(LoadContext.createQuery(query_str))
                .setParameter("enabled", true))
                //.setView("VatTable.full"))
        List<VatTable> vat_tbl = dataManager.loadList(loadContext)        

// Code ------

------ Full Stack Exception

java.lang.IllegalArgumentException: MetaClass not found for contactsclass
	at com.haulmont.cuba.core.sys.CachingMetadataSession.getClassNN(CachingMetadataSession.java:70)
	at com.haulmont.cuba.core.sys.MetadataImpl.getClassNN(MetadataImpl.java:319)
	at com.haulmont.cuba.core.sys.PersistenceSecurityImpl.applyConstraints(PersistenceSecurityImpl.java:75)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:84)
	at com.haulmont.cuba.core.sys.PerformanceLogInterceptor.aroundInvoke(PerformanceLogInterceptor.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:616)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy59.applyConstraints(Unknown Source)
	at com.haulmont.cuba.core.app.DataServiceQueryBuilder.applyConstraints(DataServiceQueryBuilder.java:187)
	at com.haulmont.cuba.core.app.DataServiceQueryBuilder.getQuery(DataServiceQueryBuilder.java:127)
	at com.haulmont.cuba.core.app.RdbmsStore.createQuery(RdbmsStore.java:633)
	at com.haulmont.cuba.core.app.RdbmsStore.loadList(RdbmsStore.java:224)
	at com.haulmont.cuba.core.app.DataManagerBean.loadList(DataManagerBean.java:74)
	at com.haulmont.cuba.core.app.DataServiceBean.loadList(DataServiceBean.java:54)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:84)
	at com.haulmont.cuba.core.sys.ServiceInterceptor.aroundInvoke(ServiceInterceptor.java:117)
	at sun.reflect.GeneratedMethodAccessor121.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:616)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy82.loadList(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.haulmont.cuba.core.sys.remoting.LocalServiceInvokerImpl.invoke(LocalServiceInvokerImpl.java:94)
	at com.haulmont.cuba.web.sys.remoting.LocalServiceProxy$LocalServiceInvocationHandler.invoke(LocalServiceProxy.java:154)
	at com.sun.proxy.$Proxy260.loadList(Unknown Source)
	at com.haulmont.cuba.client.sys.DataManagerClientImpl.loadList(DataManagerClientImpl.java:57)
	at com.haulmont.cuba.core.global.DataManager$loadList.call(Unknown Source)
	at pro.sysonline.contacts.web.invoice.InvoiceEdit.init(InvoiceEdit.groovy:124)
	at com.haulmont.cuba.gui.WindowManager.init(WindowManager.java:1247)
	at com.haulmont.cuba.gui.WindowManager.initWrapperFrame(WindowManager.java:1236)
	at com.haulmont.cuba.gui.WindowManager.createWindow(WindowManager.java:581)
	at com.haulmont.cuba.gui.WindowManager.openEditor(WindowManager.java:874)
	at com.haulmont.cuba.web.WebWindowManager.openEditor(WebWindowManager.java:178)
	at com.haulmont.cuba.gui.components.WindowDelegate.openEditor(WindowDelegate.java:260)
	at com.haulmont.cuba.web.gui.WebWindow.openEditor(WebWindow.java:497)
	at com.haulmont.cuba.gui.components.actions.CreateAction.internalOpenEditor(CreateAction.java:294)
	at com.haulmont.cuba.gui.components.actions.CreateAction.actionPerform(CreateAction.java:254)
	at com.haulmont.cuba.web.gui.components.WebButton.performAction(WebButton.java:46)
	at com.haulmont.cuba.web.gui.components.WebButton.lambda$new$61446b05$1(WebButton.java:38)
	at sun.reflect.GeneratedMethodAccessor173.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:200)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:163)
	at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1037)
	at com.vaadin.ui.Button.fireClick(Button.java:377)
	at com.haulmont.cuba.web.toolkit.ui.CubaButton.fireClick(CubaButton.java:69)
	at com.vaadin.ui.Button$1.click(Button.java:54)
	at sun.reflect.GeneratedMethodAccessor172.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:158)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:119)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:444)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:409)
	at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
	at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:90)
	at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
	at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1435)
	at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:361)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:312)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:203)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	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:52)
	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:107)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:73)
	at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:107)
	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:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

Hi, definitevely a Groovy problem with Typed results (and collections of Typed results).
Same Service Written in Java with Entity Manager works fine.

Could you provide a test project where the problem is reproduced?

I’ll try to reduce my project with local database whithin a couple of days,

Thanks,
Fabrizio

Sorry for being so late, but I had some problems.
I think now I understand why problem presents only in Groovy and not in Java.

—>>> “select f from contacts$MembershipFee f where f.artistInfo.id = :artistId” (double quotes) Java

—>>> ‘select f from contacts$MembershipFee f where f.artistInfo.id = :artistId’ (single quotes) Groovy

$ sign is reserved in Groovy GPath, so to if you use double quotes Query String is not a full string but contains GPath Operator.

If present $ sign can be followed only by number characters not letters. (Stackoverflow link)

Solution: use single quotes as String delimiter. (very tricky problem, solution is where you never think)

http://groovy-lang.org/syntax.html

4.7. Dollar slashy string

Dollar slashy strings are multiline GStrings delimited with an opening $/ and and a closing /$. The escaping character is the dollar sign, and it can escape another dollar, or a forward slash. But both dollar and forward slashes don’t need to be escaped, except to escape the dollar of a string subsequence that would start like a GString placeholder sequence, or if you need to escape a sequence that would start like a closing dollar slashy string delimiter.

Thanks anyway

1 Like