From 36c9e2879c3f5fbb969ad9134c005438d56e7965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Le=20Ray?= Date: Mon, 9 Apr 2018 08:17:02 +0200 Subject: [PATCH] entity: add new entity-listener tag 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. --- .../src/main/resources/domain-models.xsd | 24 ++++++++++++ .../axelor/tools/x2j/pojo/Annotation.groovy | 10 +++-- .../com/axelor/tools/x2j/pojo/Entity.groovy | 38 +++++++++++++------ 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/axelor-core/src/main/resources/domain-models.xsd b/axelor-core/src/main/resources/domain-models.xsd index 9e396a2254..dc8cc14205 100644 --- a/axelor-core/src/main/resources/domain-models.xsd +++ b/axelor-core/src/main/resources/domain-models.xsd @@ -793,6 +793,14 @@ Entity represent domain model. + + + + Define class containing annotated methods (@PrePersist, etc.) that will be called + during entity lifecycle. + + + @@ -1143,4 +1151,20 @@ + + + + + + + FQDN of the listener class + + + + + + + + diff --git a/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Annotation.groovy b/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Annotation.groovy index 85b9909cfe..850498693f 100644 --- a/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Annotation.groovy +++ b/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Annotation.groovy @@ -26,7 +26,7 @@ class Annotation { boolean empty Entity entity - + ImportManager importManager Annotation(Entity entity, String name) { @@ -37,7 +37,7 @@ class Annotation { this(entity.importManager, name, empty) this.entity = entity } - + Annotation(ImportManager importer, String name, boolean empty) { this.importManager = importer this.name = "@" + importer.importType(name) @@ -91,13 +91,17 @@ class Annotation { } Annotation add(String param, List values, boolean quote, boolean unwrapSingle) { + add(param, values, quote, unwrapSingle, true); + } + + Annotation add(String param, List values, boolean quote, boolean unwrapSingle, boolean importTypes) { if (values == null) return this; values = values.collect { if (it instanceof Annotation) return it - quote ? this.quote(it) : importManager.importType(it) + quote ? this.quote(it) : (importTypes ? importManager.importType(it) : it) } def value = unwrapSingle && values.size() == 1 ? values[0] : wrap(values) diff --git a/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Entity.groovy b/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Entity.groovy index c5db9bf20f..2170adabab 100644 --- a/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Entity.groovy +++ b/axelor-gradle/src/main/groovy/com/axelor/tools/x2j/pojo/Entity.groovy @@ -23,7 +23,7 @@ import com.axelor.common.Inflector import com.axelor.tools.x2j.Utils class Entity { - + private static Set INTERNAL_PACKAGES = [ 'com.axelor.auth.db', 'com.axelor.meta.db', @@ -38,7 +38,7 @@ class Entity { String module String namespace - + String repoNamespace String tablePrefix @@ -75,6 +75,8 @@ class Entity { List finders + List listeners + Map propertyMap Property nameField @@ -82,9 +84,9 @@ class Entity { private Repository repository private ImportManager importManager - + private String extraImports - + private String extraCode private Track track @@ -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) { @@ -202,6 +205,9 @@ class Entity { case "track": track = new Track(this, it) break + case "entity-listener": + listeners += it.'@listenerClass'.text() + '.class' + break default: Property field = new Property(this, it) if (modelClass && !field.simple) { @@ -232,7 +238,7 @@ class Entity { properties.add(propertyMap.get("attrs")); } } - + Repository getRepository() { return this.repository } @@ -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)) { @@ -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) { @@ -309,7 +316,7 @@ class Entity { if (!interfaces || interfaces.trim() == "") return "" return " implements " + interfaces } - + String getExtendsImplementStmt() { if (modelClass) { importType('javax.persistence.Transient') @@ -319,7 +326,7 @@ class Entity { } return " extends " + getBaseClass() + getImplementStmt() } - + String getAbstractStmt() { return modelClass ? "abstract " : "" } @@ -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" @@ -389,7 +396,7 @@ class Entity { private List getHashables() { return properties.findAll { p -> p.hashKey } } - + boolean isModelClass() { return modelClass; } @@ -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 } @@ -569,6 +577,12 @@ class Entity { return track.$track() } + Annotation $listeners() { + if(listeners.empty) return null; + return new Annotation(this, "javax.persistence.EntityListeners") + .add("value", listeners, false, false, false) + } + @Override String toString() { def names = fields.collect { it.name }