Skip to content

Commit

Permalink
entity: add new entity-listener tag
Browse files Browse the repository at this point in the history
Allow entities to declare listeners that'll be invoked during lifecycle.
This allows to perform consistency checks in a more reliable way than
overriding repository save() method as listeners are called even in case
of cascading persist.
Annotation has been modified to allow avoiding imports since for
@EntityListeners we need to pass .class which doesn't play well with
autoimport. Alternative would have been to import and append '.class' to
annotation param by the mean of another boolean parameter.
  • Loading branch information
Sébastien Le Ray committed Dec 11, 2018
1 parent e74601d commit 4b169b6
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 12 deletions.
24 changes: 24 additions & 0 deletions axelor-core/src/main/resources/domain-models.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,14 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="entity-listener" type="dm:EntityListener" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
Define class containing annotated methods (@PrePersist, etc.) that will be called
during entity lifecycle.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>

<xsd:attribute use="required" name="name">
Expand Down Expand Up @@ -1157,4 +1165,20 @@
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>

<xsd:complexType name="EntityListener">
<xsd:attribute name="class" use="required">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
FQDN of the listener class
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:pattern
value="(([a-z][a-zA-Z0-9_]+)(\.[a-z][a-zA-Z0-9_]+)*\.)?([A-Z][a-zA-Z0-9_]+)" />
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:schema>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.axelor.common.Inflector
import com.axelor.tools.x2j.Utils

class Entity {

private static Set<String> INTERNAL_PACKAGES = [
'com.axelor.auth.db',
'com.axelor.meta.db',
Expand All @@ -38,7 +38,7 @@ class Entity {
String module

String namespace

String repoNamespace

String tablePrefix
Expand Down Expand Up @@ -75,16 +75,18 @@ class Entity {

List<String> finders

List<String> listeners

Map<String, Property> propertyMap

Property nameField

private Repository repository

private ImportManager importManager

private String extraImports

private String extraCode

private Track track
Expand Down Expand Up @@ -149,12 +151,13 @@ class Entity {
repository = new Repository(this)
repository.concrete = node.@repository != "abstract"
}

properties = []
propertyMap = [:]
constraints = []
indexes = []
finders = []
listeners = []
extraCode = null

if (interfaces) {
Expand Down Expand Up @@ -202,6 +205,9 @@ class Entity {
case "track":
track = new Track(this, it)
break
case "entity-listener":
listeners += it.'@class'.text() + '.class'
break
default:
Property field = new Property(this, it)
if (modelClass && !field.simple) {
Expand Down Expand Up @@ -232,7 +238,7 @@ class Entity {
properties.add(propertyMap.get("attrs"));
}
}

Repository getRepository() {
return this.repository
}
Expand All @@ -247,7 +253,7 @@ class Entity {
}

void merge(Entity other) {

for (Property prop : other.properties) {
Property existing = propertyMap.get(prop.name)
if (isCompatible(existing, prop)) {
Expand All @@ -263,10 +269,11 @@ class Entity {
}
}
}

indexes.addAll(other.indexes)
constraints.addAll(other.constraints)
finders.addAll(other.finders)
listeners.addAll(other.listeners)

if (other.track) {
if (track == null || other.track.replace) {
Expand Down Expand Up @@ -309,7 +316,7 @@ class Entity {
if (!interfaces || interfaces.trim() == "") return ""
return " implements " + interfaces
}

String getExtendsImplementStmt() {
if (modelClass) {
importType('javax.persistence.Transient')
Expand All @@ -319,7 +326,7 @@ class Entity {
}
return " extends " + getBaseClass() + getImplementStmt()
}

String getAbstractStmt() {
return modelClass ? "abstract " : ""
}
Expand Down Expand Up @@ -380,7 +387,7 @@ class Entity {
String getExtraCode() {
return stripCode(extraCode, "\n\t");
}

String getExtraImports() {
if (!extraImports || extraImports.trim().isEmpty()) return "";
return "\n" + Utils.stripCode(extraImports, "\n") + "\n"
Expand All @@ -389,7 +396,7 @@ class Entity {
private List<Property> getHashables() {
return properties.findAll { p -> p.hashKey }
}

boolean isModelClass() {
return modelClass;
}
Expand Down Expand Up @@ -487,6 +494,7 @@ class Entity {
all += $strategy()
all += $track()
all += $mappedSuperClass()
all += $listeners()

return all.grep { it != null }.flatten()
.grep { Annotation a -> !a.empty }
Expand Down Expand Up @@ -569,6 +577,12 @@ class Entity {
return track.$track()
}

Annotation $listeners() {
if(listeners.empty) return null;
return new Annotation(this, "javax.persistence.EntityListeners")
.add("{ ${ listeners.collect { importType(it) + '.class' }.join(', ') } }", false)
}

@Override
String toString() {
def names = fields.collect { it.name }
Expand Down

0 comments on commit 4b169b6

Please sign in to comment.