Author: simoneg
Date: Thu May 10 16:40:38 2012
New Revision: 1336781
URL: http://svn.apache.org/viewvc?rev=1336781&view=rev
Log:
Added JPA annotation parsing integrated with BeanData, since it's useful in
many places
Added:
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
Modified:
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj
Modified:
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj
URL:
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj?rev=1336781&r1=1336780&r2=1336781&view=diff
==============================================================================
---
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj
(original)
+++
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj
Thu May 10 16:40:38 2012
@@ -31,28 +31,22 @@ import org.apache.magma.validation.Valid
public aspect AddDefaultJPAValidation {
- declare precedence : AddDefaultJPAValidation,
AddValidatorInPropertyInfo;
+ declare precedence : PropertyInfoAdditions, AddDefaultJPAValidation,
AddValidatorInPropertyInfo;
- private boolean PropertyInfo.jpaTransient = false;
-
- public boolean PropertyInfo.isJpaTransient() {
- return jpaTransient;
- }
-
public static final String MagDefaultLayers.DATABASE = "database";
after(PropertyInfo info, PropertyDescriptor desc, Class beanClass) :
execution(* PropertyInfo.init(PropertyDescriptor, Class)) &&
this(info) && args(desc, beanClass) {
if (info.getType() == null) return;
- if (info.isReadable() &&
desc.getReadMethod().isAnnotationPresent(Transient.class)) info.jpaTransient =
true;
if (!info.getType().equals(String.class)) return;
if (!info.isWriteable() || !info.isReadable()) return;
CompoundValidator val = info.getValidator();
if (val != null && val.getValidator(DatabaseValidator.class) !=
null) return;
-
+
+ // Need this, at this stage we don't yet have a fully
initialized BeanData, we are right in the middle of it
boolean isjpa = false;
isjpa |= beanClass.isAnnotationPresent(Entity.class);
isjpa |= beanClass.isAnnotationPresent(Embeddable.class);
Added:
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
URL:
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj?rev=1336781&view=auto
==============================================================================
---
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
(added)
+++
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
Thu May 10 16:40:38 2012
@@ -0,0 +1,173 @@
+package org.apache.magma.database;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.Entity;
+import javax.persistence.PostLoad;
+import javax.persistence.PostPersist;
+import javax.persistence.PostRemove;
+import javax.persistence.PostUpdate;
+import javax.persistence.PrePersist;
+import javax.persistence.PreRemove;
+import javax.persistence.PreUpdate;
+
+import org.apache.magma.beans.BeanData;
+import org.apache.magma.beans.MagmaBeanSupport;
+import org.apache.magma.beans.PropertyInfo;
+import org.apache.magma.database.DatabasePersisted;
+
+public aspect BeanDataAdditions {
+
+ private List<PropertyInfo> BeanData.jpaBasicFields = null;
+ private List<PropertyInfo> BeanData.jpaRelationFields = null;
+ private PropertyInfo BeanData.jpaIdField = null;
+ private PropertyInfo BeanData.jpaVersionField = null;
+
+ private boolean BeanData.jpaClass = false;
+ private String BeanData.jpaTableName = null;
+ private Class<? extends DatabasePersisted> BeanData.jpaSuper = null;
+
+ private Map<Class<? extends Annotation>, List<Method>>
BeanData.jpaCallbacks = null;
+
+
+ private void BeanData.buildJpaFieldList() {
+ List<String> flds = new ArrayList<String>(getPropertyNames());
+ Collections.sort(flds);
+ jpaBasicFields = new ArrayList<PropertyInfo>();
+ jpaRelationFields = new ArrayList<PropertyInfo>();
+ for (String name : flds) {
+ PropertyInfo info = getProperty(name);
+ if (info.isJpaTransient()) continue;
+ if (info.isJpaId()) {
+ jpaIdField = info;
+ } else if (info.isJpaVersion()) {
+ jpaVersionField = info;
+ } else {
+ if (!info.isReadable()) continue;
+ if (info.isBasicType()) {
+ if (!info.isWriteable()) continue;
+ jpaBasicFields.add(info);
+ } else if (info.getJpaRelation() != null ||
info.isMap()) {
+ jpaRelationFields.add(info);
+ }
+ }
+ }
+ }
+
+ public List<PropertyInfo> BeanData.getJpaBasicFields() {
+ if (jpaBasicFields == null) buildJpaFieldList();
+ return jpaBasicFields;
+ }
+
+ public List<PropertyInfo> BeanData.getJpaRelationFields() {
+ if (jpaRelationFields == null) buildJpaFieldList();
+ return jpaRelationFields;
+ }
+
+ public PropertyInfo BeanData.getJpaIdField() {
+ if (jpaIdField == null) buildJpaFieldList();
+ return jpaIdField;
+ }
+
+ public PropertyInfo BeanData.getJpaVersionField() {
+ if (jpaVersionField == null) buildJpaFieldList();
+ return jpaVersionField;
+ }
+
+ public boolean BeanData.isJpaClass() {
+ return this.jpaClass;
+ }
+
+ public String BeanData.getJpaTableName() {
+ return this.jpaTableName;
+ }
+
+ public Class<? extends DatabasePersisted> BeanData.getJpaSuper() {
+ return this.jpaSuper;
+ }
+
+ public List<Method> BeanData.getJpaHandlers(Class<? extends Annotation>
annotation) {
+ if (this.jpaCallbacks == null) return null;
+ return this.jpaCallbacks.get(annotation);
+ }
+
+ after(BeanData bd) :
+ execution(BeanData.new(..))
+ && this(bd) {
+
+ Class<? extends MagmaBeanSupport> clzz = bd.getBeanClass();
+ if (!DatabasePersisted.class.isAssignableFrom(clzz)) return;
+
+ scanCallbacks(bd,clzz);
+ Class sup = clzz.getSuperclass();
+ BeanData supbd = null;
+ while (sup != null) {
+ BeanData sbd = BeanData.getFor(sup);
+ if (sbd.jpaClass) {
+ bd.jpaSuper = sup;
+ supbd = sbd;
+ scanCallbacks(sbd, sup);
+ }
+ sup = sup.getSuperclass();
+ }
+
+ Entity ent = clzz.getAnnotation(Entity.class);
+ if (ent != null) {
+ bd.jpaClass = true;
+ bd.jpaTableName = ent.name();
+ }
+
+ if (!bd.jpaClass) return;
+
+ if (bd.jpaTableName == null || bd.jpaTableName.length() == 0) {
+ if (supbd != null) {
+ bd.jpaTableName = supbd.jpaTableName;
+ } else {
+ bd.jpaTableName =
clzz.getSimpleName().toLowerCase();
+ }
+ }
+
+ }
+
+ private static List<Class<? extends Annotation>> callbacks = new
ArrayList<Class<? extends Annotation>>();
+
+ static {
+ callbacks.add(PrePersist.class);
+ callbacks.add(PostPersist.class);
+
+ callbacks.add(PreUpdate.class);
+ callbacks.add(PostUpdate.class);
+
+ callbacks.add(PreRemove.class);
+ callbacks.add(PostRemove.class);
+
+ callbacks.add(PostLoad.class);
+ }
+
+ private static void scanCallbacks(BeanData bd, Class clzz) {
+ Method[] meths = clzz.getDeclaredMethods();
+ for (Method m : meths) {
+ for (Class<? extends Annotation> ann : callbacks) {
+ if (m.isAnnotationPresent(ann)) {
+ if (!m.isAccessible()) {
+ m.setAccessible(true);
+ }
+ if (bd.jpaCallbacks == null)
+ bd.jpaCallbacks = new
HashMap<Class<? extends Annotation>, List<Method>>();
+ List<Method> mlist =
bd.jpaCallbacks.get(ann);
+ if (mlist == null) {
+ mlist = new ArrayList<Method>();
+ bd.jpaCallbacks.put(ann, mlist);
+ }
+ mlist.add(m);
+ }
+ }
+ }
+ }
+}
Added:
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
URL:
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java?rev=1336781&view=auto
==============================================================================
---
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
(added)
+++
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
Thu May 10 16:40:38 2012
@@ -0,0 +1,10 @@
+package org.apache.magma.database;
+
+public enum JpaRelations {
+
+ OneToOne,
+ OneToMany,
+ ManyToMany,
+ ManyToOne
+
+}
Added:
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
URL:
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj?rev=1336781&view=auto
==============================================================================
---
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
(added)
+++
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
Thu May 10 16:40:38 2012
@@ -0,0 +1,172 @@
+package org.apache.magma.database;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Transient;
+import javax.persistence.Version;
+
+import org.apache.magma.beans.PropertyInfo;
+
+public aspect PropertyInfoAdditions {
+
+ private String PropertyInfo.jpaColName = null;
+ private boolean PropertyInfo.jpaEmbedded = false;
+ private boolean PropertyInfo.jpaId = false;
+ private boolean PropertyInfo.jpaVersion = false;
+ private boolean PropertyInfo.jpaTransient = false;
+
+ private JpaRelations PropertyInfo.jpaRelation = null;
+ private CascadeType[] PropertyInfo.jpaCascade = null;
+ private boolean PropertyInfo.jpaDeleteOrphans = false;
+ private String PropertyInfo.jpaMappedBy = null;
+
+
+
+ public boolean PropertyInfo.isJpaTransient() {
+ return this.jpaTransient;
+ }
+
+ public String PropertyInfo.getJpaColName() {
+ return this.jpaColName;
+ }
+
+ public boolean PropertyInfo.isJpaEmbedded() {
+ return this.jpaEmbedded;
+ }
+
+ public boolean PropertyInfo.isJpaVersion() {
+ return this.jpaVersion;
+ }
+
+ public boolean PropertyInfo.isJpaId() {
+ return this.jpaId;
+ }
+
+ public CascadeType[] PropertyInfo.getJpaCascadeType() {
+ return this.jpaCascade;
+ }
+
+ public JpaRelations PropertyInfo.getJpaRelation() {
+ return this.jpaRelation;
+ }
+
+ public boolean PropertyInfo.isJpaDeleteOrphans() {
+ return this.jpaDeleteOrphans;
+ }
+
+
+ after(PropertyInfo info, PropertyDescriptor desc, Class beanClass) :
+ execution(* PropertyInfo.init(PropertyDescriptor, Class))
+ && this(info)
+ && args(desc, beanClass) {
+
+ Method rm = desc.getReadMethod();
+ if (rm == null) return;
+
+ Column col = rm.getAnnotation(Column.class);
+ if (col != null) {
+ info.jpaColName = col.name();
+ }
+ if (info.jpaColName == null || info.jpaColName.length() == 0) {
+ info.jpaColName = info.getName();
+ }
+
+ Embedded emb = rm.getAnnotation(Embedded.class);
+ if (emb != null) {
+ info.jpaEmbedded = true;
+ }
+
+ Id id = rm.getAnnotation(Id.class);
+ if (id != null)
+ info.jpaId = true;
+
+ Version ver = rm.getAnnotation(Version.class);
+ if (ver != null)
+ info.jpaVersion = true;
+
+ if (rm.isAnnotationPresent(Transient.class))
+ info.jpaTransient = true;
+
+
+ {
+ OneToOne assoc = rm.getAnnotation(OneToOne.class);
+ if (assoc != null) {
+ info.jpaCascade = assoc.cascade();
+ info.jpaRelation = JpaRelations.OneToOne;
+ info.jpaMappedBy = assoc.mappedBy();
+ info.jpaDeleteOrphans |=
checkOrphanRemoval(assoc);
+ }
+ }
+
+ {
+ OneToMany assoc = rm.getAnnotation(OneToMany.class);
+ if (assoc != null) {
+ info.jpaCascade = assoc.cascade();
+ info.jpaRelation = JpaRelations.OneToMany;
+ info.jpaMappedBy = assoc.mappedBy();
+ info.jpaDeleteOrphans |=
checkOrphanRemoval(assoc);
+ }
+ }
+
+ {
+ ManyToOne assoc = rm.getAnnotation(ManyToOne.class);
+ if (assoc != null) {
+ info.jpaCascade = assoc.cascade();
+ info.jpaRelation = JpaRelations.ManyToMany;
+ info.jpaDeleteOrphans |=
checkOrphanRemoval(assoc);
+ }
+ }
+
+ {
+ ManyToMany assoc = rm.getAnnotation(ManyToMany.class);
+ if (assoc != null) {
+ info.jpaCascade = assoc.cascade();
+ info.jpaRelation = JpaRelations.ManyToOne;
+ info.jpaMappedBy = assoc.mappedBy();
+ info.jpaDeleteOrphans |=
checkOrphanRemoval(assoc);
+ }
+ }
+
+ if (!info.jpaDeleteOrphans) {
+ Annotation[] anns = rm.getAnnotations();
+ for (Annotation ann : anns) {
+ info.jpaDeleteOrphans |=
ann.annotationType().getName().equals("org.apache.openjpa.persistence.ElementDependent");
+ // TODO eventually parse also other old ORM
specific options
+ }
+ }
+ }
+
+ private boolean checkOrphanRemoval(Annotation a) {
+ Method meth = null;
+ try {
+ meth = a.getClass().getMethod("orphanRemoval");
+ } catch (SecurityException e) {
+ // TODO maybe we should warn for this one?
+ return false;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ if (meth == null) return false;
+ if (!meth.getReturnType().equals(Boolean.TYPE)) return false;
+ try {
+ return (Boolean)meth.invoke(a);
+ } catch (IllegalAccessException e) {
+ // TODO maybe we should warn for this one?
+ return false;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]