2

I'm struggling with a validation I would like to implement. I would like to verify that every Methods from a Service that start with update must have the @Transactional annotation. So far I have made a concept that gives me the methods from my service class that start with update (e.g. updateInvoice). But i have no idea how to build a constraint that select the methods wich have no @Transaction annotation.

rogergl
  • 3,501
  • 2
  • 30
  • 49

2 Answers2

3

I'd recommend to define some concepts representing your key elements to define constraints on them, i.e.

Your services:

<concept id="service:ServiceClass">
  <description>Adds a label "Service" to every class annotated by "@com.mycompany.services.Service"</description>
  <cypher><![CDATA[
  MATCH
    (service:Type:Class)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(serviceAnnotationType)
  SET
    service:Service
  WHERE
    serviceAnnotationType.fqn = "com.mycompany.services.Service"
  RETURN
    service   
  ]]>
  </cypher>
</concept>

Your transacted methods:

<concept id="service:TransactMethod">
  <description>Adds a label "Transact" to every method annotated by "@com.mycompany.services.Transact"</description>
  <cypher><![CDATA[
  MATCH
    (method:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(transactAnnotationType)
  SET
    method:Transact
  WHERE
    transactAnnotationType.fqn = "com.mycompany.services.Transact"
  RETURN
    method   
  ]]>
  </cypher>
</concept>

Your constraint:

<constraint id="service:AllUpdateMethodsMustBeTransacted">
  <requiresConcept refId="service:ServiceClass" />
  <requiresConcept refId="service:TransactMethod" />
  <description>All update methods must be transacted</description>
  <cypher><![CDATA[
  MATCH
    (service:Service:Class)-[:DECLARES]->(updateMethod:Method)
  WHERE
    updateMethod.name =~ "update.*" // even this could be extracted to a concept
    and not updateMethod:Transact
  RETURN
    updateMethod
  ]]>
  </cypher>
</constraint >

This approach has several advantages:

  • You're getting more rules now but each of them is much better readable (especially the constaint), because you're using terms that you defined for your design
  • It's very likely that you will need the concepts "Service" and "Transact" for other constraints too - now just use the labels
  • If you're creating a Maven site you get a report about all the concepts in your design (i.e. wich service implementations do currently exist)
Dirk Mahler
  • 1,186
  • 1
  • 6
  • 7
1

The following seems to work:

match
   (aType:Type:Class)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(anAnnotationType:Type),
   (aType:Type)-[:DECLARES]->(aMethod:Method)
optional match
   (aMethod)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(tType:Type)
with anAnnotationType, aMethod, tType
where
    anAnnotationType.fqn = "com.mycompany.services.Service" 
    and aMethod.name =~ "update.*"
    and ((tType is null) or not (tType.fqn = "com.mycompany.services.Transact"))
return
    aMethod.name, tType
rogergl
  • 3,501
  • 2
  • 30
  • 49