You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2020/11/19 14:10:29 UTC
[cayenne] 01/04: Added the ability to create callbacks via
annotations
This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit c5de542a0f3977dae9835262c898c983b49fbe3e
Author: andreykravchenko <an...@objectstyle.com>
AuthorDate: Thu Nov 5 13:14:42 2020 +0300
Added the ability to create callbacks via annotations
---
.../org/apache/cayenne/map/EntityResolver.java | 22 +++++
.../java/org/apache/cayenne/map/AnnotationIT.java | 82 ++++++++++++++++
.../testdo/annotation/ArtistAnnotation.java | 70 +++++++++++++
.../testdo/annotation/auto/_ArtistAnnotation.java | 108 +++++++++++++++++++++
.../cayenne/unit/di/server/CayenneProjects.java | 1 +
.../cayenne/unit/di/server/SchemaBuilder.java | 3 +-
.../test/resources/annotation/cayenne-project.xml | 7 ++
.../resources/annotation/datamapAnnotation.map.xml | 17 ++++
8 files changed, 309 insertions(+), 1 deletion(-)
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/EntityResolver.java b/cayenne-server/src/main/java/org/apache/cayenne/map/EntityResolver.java
index 8b945da..ebe7171 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/EntityResolver.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/EntityResolver.java
@@ -22,6 +22,7 @@ package org.apache.cayenne.map;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -29,6 +30,7 @@ import java.util.concurrent.atomic.AtomicLong;
import org.apache.cayenne.Persistent;
import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
+import org.apache.cayenne.annotation.*;
import org.apache.cayenne.reflect.ClassDescriptor;
import org.apache.cayenne.reflect.ClassDescriptorMap;
import org.apache.cayenne.reflect.FaultFactory;
@@ -145,6 +147,26 @@ public class EntityResolver implements MappingNamespace, Serializable {
for (ObjEntity entity : getObjEntities()) {
Class<?> entityClass = entity.getJavaClass();
+ for (Method m : entityClass.getDeclaredMethods()) {
+ if (m.isAnnotationPresent(PostAdd.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.POST_ADD, entityClass, m.getName());
+ } else if (m.isAnnotationPresent(PrePersist.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.PRE_PERSIST, entityClass, m.getName());
+ } else if (m.isAnnotationPresent(PostPersist.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.POST_PERSIST, entityClass, m.getName());
+ } else if (m.isAnnotationPresent(PreUpdate.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.PRE_UPDATE, entityClass, m.getName());
+ } else if (m.isAnnotationPresent(PostUpdate.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.POST_UPDATE, entityClass, m.getName());
+ } else if (m.isAnnotationPresent(PreRemove.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.PRE_REMOVE, entityClass, m.getName());
+ } else if (m.isAnnotationPresent(PostRemove.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.POST_REMOVE, entityClass, m.getName());
+ } else if (m.isAnnotationPresent(PostLoad.class)) {
+ callbackRegistry.addCallback(LifecycleEvent.POST_LOAD, entityClass, m.getName());
+ }
+ }
+
CallbackDescriptor[] callbacks = entity.getCallbackMap().getCallbacks();
for (CallbackDescriptor callback : callbacks) {
for (String method : callback.getCallbackMethods()) {
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/map/AnnotationIT.java b/cayenne-server/src/test/java/org/apache/cayenne/map/AnnotationIT.java
new file mode 100644
index 0000000..232cfc4
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/AnnotationIT.java
@@ -0,0 +1,82 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.map;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.reflect.LifecycleCallbackRegistry;
+import org.apache.cayenne.testdo.annotation.ArtistAnnotation;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Test;
+
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 4.2
+ */
+@UseServerRuntime(CayenneProjects.ANNOTATION)
+public class AnnotationIT extends ServerCase {
+
+ @Inject
+ private ObjectContext objectContext;
+
+ @Test
+ public void testAvailableCallback() {
+
+ LifecycleCallbackRegistry lifecycleCallbackRegistry = objectContext.getEntityResolver().getCallbackRegistry();
+
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.POST_ADD));
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.PRE_PERSIST));
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.POST_PERSIST));
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.POST_LOAD));
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.PRE_UPDATE));
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.POST_UPDATE));
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.PRE_REMOVE));
+ assertFalse(lifecycleCallbackRegistry.isEmpty(LifecycleEvent.POST_REMOVE));
+ }
+
+ @Test
+ public void testWorkCallback() {
+ ArtistAnnotation artist = objectContext.newObject(ArtistAnnotation.class);
+ assertEquals(artist.getPostCallback(), "testPostAdd");
+ assertNull(artist.getPreCallback());
+
+ objectContext.commitChanges();
+ assertEquals(artist.getPostCallback(), "testPostPersist");
+ assertEquals(artist.getPreCallback(), "testPrePersist");
+
+ artist = ObjectSelect.query(ArtistAnnotation.class).selectFirst(objectContext);
+ assertEquals(artist.getPostCallback(), "testPostLoad");
+
+ artist.setPostCallback(null);
+ objectContext.commitChanges();
+ assertEquals(artist.getPostCallback(), "testPostUpdate");
+ assertEquals(artist.getPreCallback(), "testPreUpdate");
+
+ objectContext.deleteObject(artist);
+ assertEquals(artist.getPreCallback(), "testPreRemove");
+ objectContext.commitChanges();
+ assertEquals(artist.getPostCallback(), "testPostRemove");
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/annotation/ArtistAnnotation.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/annotation/ArtistAnnotation.java
new file mode 100644
index 0000000..6435524
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/annotation/ArtistAnnotation.java
@@ -0,0 +1,70 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.testdo.annotation;
+
+import org.apache.cayenne.annotation.*;
+import org.apache.cayenne.testdo.annotation.auto._ArtistAnnotation;
+
+public class ArtistAnnotation extends _ArtistAnnotation {
+
+ private static final long serialVersionUID = 1L;
+
+ @PostAdd
+ protected void testPostAdd() {
+ postCallback = "testPostAdd";
+ }
+
+ @PostPersist
+ protected void testPostPersist() {
+ postCallback = "testPostPersist";
+ }
+
+ @PrePersist
+ protected void testPrePersist() {
+ preCallback = "testPrePersist";
+ }
+
+ @PostUpdate
+ protected void testPostUpdate() {
+ postCallback = "testPostUpdate";
+ }
+
+ @PreUpdate
+ protected void testPreUpdate() {
+ preCallback = "testPreUpdate";
+ }
+
+ @PostLoad
+ protected void testPostLoad() {
+ postCallback = "testPostLoad";
+ }
+
+ @PostRemove
+ protected void testPostRemove() {
+ postCallback = "testPostRemove";
+ }
+
+ @PreRemove
+ protected void testPreRemove() {
+ preCallback = "testPreRemove";
+ }
+
+ @Override
+ protected void onPostAdd() { }
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/annotation/auto/_ArtistAnnotation.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/annotation/auto/_ArtistAnnotation.java
new file mode 100644
index 0000000..5e52750
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/annotation/auto/_ArtistAnnotation.java
@@ -0,0 +1,108 @@
+package org.apache.cayenne.testdo.annotation.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
+
+/**
+ * Class _Artist was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _ArtistAnnotation extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "ID";
+
+ public static final StringProperty<String> POST_CALLBACK = PropertyFactory.createString("postCallback", String.class);
+ public static final StringProperty<String> PRE_CALLBACK = PropertyFactory.createString("preCallback", String.class);
+
+ protected String postCallback;
+ protected String preCallback;
+
+
+ public void setPostCallback(String postCallback) {
+ beforePropertyWrite("postCallback", this.postCallback, postCallback);
+ this.postCallback = postCallback;
+ }
+
+ public String getPostCallback() {
+ beforePropertyRead("postCallback");
+ return this.postCallback;
+ }
+
+ public void setPreCallback(String preCallback) {
+ beforePropertyWrite("preCallback", this.preCallback, preCallback);
+ this.preCallback = preCallback;
+ }
+
+ public String getPreCallback() {
+ beforePropertyRead("preCallback");
+ return this.preCallback;
+ }
+
+ protected abstract void onPostAdd();
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "postCallback":
+ return this.postCallback;
+ case "preCallback":
+ return this.preCallback;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "postCallback":
+ this.postCallback = (String)val;
+ break;
+ case "preCallback":
+ this.preCallback = (String)val;
+ break;
+ default:
+ super.writePropertyDirectly(propName, val);
+ }
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ writeSerialized(out);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ readSerialized(in);
+ }
+
+ @Override
+ protected void writeState(ObjectOutputStream out) throws IOException {
+ super.writeState(out);
+ out.writeObject(this.postCallback);
+ out.writeObject(this.preCallback);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ this.postCallback = (String)in.readObject();
+ this.preCallback = (String)in.readObject();
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
index 3d7d1e5..ccb392e 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
@@ -87,4 +87,5 @@ public class CayenneProjects {
public static final String LAZY_ATTRIBUTES_PROJECT = "cayenne-lazy-attributes.xml";
public static final String CAY_2666 = "cay2666/cayenne-cay-2666.xml";
public static final String CAY_2641 = "cay2641/cayenne-cay-2641.xml";
+ public static final String ANNOTATION = "annotation/cayenne-project.xml";
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
index 8067005..bc154c6 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
@@ -82,7 +82,8 @@ public class SchemaBuilder {
"qualified.map.xml", "quoted-identifiers.map.xml", "inheritance-single-table1.map.xml",
"inheritance-vertical.map.xml", "oneway-rels.map.xml", "unsupported-distinct-types.map.xml",
"array-type.map.xml", "cay-2032.map.xml", "weighted-sort.map.xml", "hybrid-data-object.map.xml",
- "java8.map.xml", "inheritance-with-enum.map.xml", "lazy-attributes.map.xml", "cay2666/datamap.map.xml", "cay2641/datamapLazy.map.xml" };
+ "java8.map.xml", "inheritance-with-enum.map.xml", "lazy-attributes.map.xml", "cay2666/datamap.map.xml", "cay2641/datamapLazy.map.xml",
+ "annotation/datamapAnnotation.map.xml" };
// hardcoded dependent entities that should be excluded
// if LOBs are not supported
diff --git a/cayenne-server/src/test/resources/annotation/cayenne-project.xml b/cayenne-server/src/test/resources/annotation/cayenne-project.xml
new file mode 100644
index 0000000..92f7f35
--- /dev/null
+++ b/cayenne-server/src/test/resources/annotation/cayenne-project.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain xmlns="http://cayenne.apache.org/schema/10/domain"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain https://cayenne.apache.org/schema/10/domain.xsd"
+ project-version="10">
+ <map name="datamapAnnotation"/>
+</domain>
diff --git a/cayenne-server/src/test/resources/annotation/datamapAnnotation.map.xml b/cayenne-server/src/test/resources/annotation/datamapAnnotation.map.xml
new file mode 100644
index 0000000..724ede8
--- /dev/null
+++ b/cayenne-server/src/test/resources/annotation/datamapAnnotation.map.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<data-map xmlns="http://cayenne.apache.org/schema/10/modelMap"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap https://cayenne.apache.org/schema/10/modelMap.xsd"
+ project-version="10">
+ <property name="defaultPackage" value="org.apache.cayenne.testdo.annotation"/>
+ <db-entity name="artist_annotation">
+ <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+ <db-attribute name="PostCallback" type="VARCHAR" length="15"/>
+ <db-attribute name="PreCallback" type="VARCHAR" length="15"/>
+ </db-entity>
+ <obj-entity name="ArtistAnnotation" className="org.apache.cayenne.testdo.annotation.ArtistAnnotation" dbEntityName="artist_annotation">
+ <obj-attribute name="postCallback" type="java.lang.String" db-attribute-path="PostCallback"/>
+ <obj-attribute name="preCallback" type="java.lang.String" db-attribute-path="PreCallback"/>
+ <post-add method-name="onPostAdd"/>
+ </obj-entity>
+</data-map>