You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2007/12/22 21:14:40 UTC

svn commit: r606484 - in /cayenne/main/trunk/framework: cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/ cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/ cayenne-jpa-unpublished/src/main/java/org/apache/cayenn...

Author: aadamchik
Date: Sat Dec 22 12:14:39 2007
New Revision: 606484

URL: http://svn.apache.org/viewvc?rev=606484&view=rev
Log:
CAY-858 A more sound enhancer algorithm that intercepts access to persistent fields
(a related enhancer improvement - will create fault tracking variables based on the mapping metadata, instead of attempting to analyze the class on the fly... this results in a much more robust and controllable behavior)

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayennePojoVisitor.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PojoVisitor.java
      - copied, changed from r606412, cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PersistentInterfaceVisitor.java
    cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaPojoVisitor.java
Removed:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PersistentInterfaceVisitor.java
Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/AccessorVisitor.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayenneEnhancerVisitorFactory.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/EnhancementHelper.java
    cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaEnhancerVisitorFactory.java
    cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/map/JpaAttributes.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/AccessorVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/AccessorVisitor.java?rev=606484&r1=606483&r2=606484&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/AccessorVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/AccessorVisitor.java Sat Dec 22 12:14:39 2007
@@ -90,8 +90,6 @@
 
         if (isEnhancedProperty(property)) {
             if (isLazyFaulted(property)) {
-                // inject fault flag field
-                helper.createField(Boolean.TYPE, "faultResolved_" + property, true);
                 return new GetterVisitor(mv, helper, property, true);
             }
             else {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayenneEnhancerVisitorFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayenneEnhancerVisitorFactory.java?rev=606484&r1=606483&r2=606484&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayenneEnhancerVisitorFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayenneEnhancerVisitorFactory.java Sat Dec 22 12:14:39 2007
@@ -28,7 +28,7 @@
 import org.objectweb.asm.commons.SerialVersionUIDAdder;
 
 /**
- * A factory of enhacing visitors.
+ * EnhancerVisitorFactory implementation based on Cayenne mapping.
  * 
  * @since 3.0
  * @author Andrus Adamchik
@@ -65,7 +65,7 @@
         if (entity != null) {
 
             // create enhancer chain
-            PersistentInterfaceVisitor e1 = new PersistentInterfaceVisitor(out);
+            PojoVisitor e1 = new CayennePojoVisitor(out, entity);
             PersistentAccessorVisitor e2 = new PersistentAccessorVisitor(e1, entity);
 
             // this ensures that both enhanced and original classes have compatible
@@ -79,8 +79,6 @@
         if (embeddable != null) {
             // create enhancer chain
             EmbeddableVisitor e1 = new EmbeddableVisitor(out);
-
-            // TODO: andrus 12/16/2007 - setter visitor...
 
             // this ensures that both enhanced and original classes have compatible
             // serialized

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayennePojoVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayennePojoVisitor.java?rev=606484&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayennePojoVisitor.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/CayennePojoVisitor.java Sat Dec 22 12:14:39 2007
@@ -0,0 +1,43 @@
+/*****************************************************************
+ *   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
+ *
+ *    http://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.enhancer;
+
+import java.util.Collection;
+
+import org.apache.cayenne.map.ObjEntity;
+import org.objectweb.asm.ClassVisitor;
+
+/**
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+class CayennePojoVisitor extends PojoVisitor {
+
+    protected ObjEntity entity;
+
+    CayennePojoVisitor(ClassVisitor visitor, ObjEntity entity) {
+        super(visitor);
+        this.entity = entity;
+    }
+
+    @Override
+    protected Collection<String> getLazilyFaultedProperties() {
+        return entity.getRelationshipMap().keySet();
+    }
+}

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/EnhancementHelper.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/EnhancementHelper.java?rev=606484&r1=606483&r2=606484&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/EnhancementHelper.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/EnhancementHelper.java Sat Dec 22 12:14:39 2007
@@ -58,11 +58,19 @@
         return fieldPrefix + propertyName;
     }
 
+    /**
+     * Resets helper to process a given class. Must be called repeatedly before each class
+     * is processed.
+     */
     public void reset(String className) {
         // assuming no primitives or arrays
         this.currentClass = Type.getType("L" + className + ";");
     }
 
+    /**
+     * Appends an interface to a String array of interfaces, returning the resulting
+     * expanded array.
+     */
     public String[] addInterface(String[] interfaces, Class<?> newInterface) {
 
         String name = Type.getInternalName(newInterface);

Copied: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PojoVisitor.java (from r606412, cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PersistentInterfaceVisitor.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PojoVisitor.java?p2=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PojoVisitor.java&p1=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PersistentInterfaceVisitor.java&r1=606412&r2=606484&rev=606484&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PersistentInterfaceVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/enhancer/PojoVisitor.java Sat Dec 22 12:14:39 2007
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.enhancer;
 
+import java.util.Collection;
+
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
@@ -26,19 +28,19 @@
 import org.objectweb.asm.Type;
 
 /**
- * Enhances classes passed through the visitor to add {@link Persistent} interface to
- * them, and fields and methods to support its implementation.
+ * Enhances classes passed through the visitor, ensuring that the resulting class
+ * implements {@link Persistent} interface as well as supports lazy faulting.
  * 
  * @since 3.0
  * @author Andrus Adamchik
  */
-public class PersistentInterfaceVisitor extends ClassAdapter {
+public abstract class PojoVisitor extends ClassAdapter {
 
     static String ENHANCED_INTERFACE_SIG = Type.getInternalName(Persistent.class);
 
     protected EnhancementHelper helper;
 
-    public PersistentInterfaceVisitor(ClassVisitor visitor) {
+    public PojoVisitor(ClassVisitor visitor) {
         super(visitor);
         this.helper = new EnhancementHelper(this);
     }
@@ -65,15 +67,19 @@
 
         helper.reset(name);
         interfaces = helper.addInterface(interfaces, Persistent.class);
-
         super.visit(version, access, name, signature, superName, interfaces);
     }
 
     @Override
     public void visitEnd() {
-        // per ASM docs, 'visitEnd' is the only correct place to add class members
         helper.createProperty(ObjectId.class, "objectId");
         helper.createProperty(ObjectContext.class, "objectContext", true);
         helper.createProperty(Integer.TYPE, "persistenceState");
+
+        for (String property : getLazilyFaultedProperties()) {
+            helper.createField(Boolean.TYPE, "faultResolved_" + property, true);
+        }
     }
+
+    protected abstract Collection<String> getLazilyFaultedProperties();
 }

Modified: cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaEnhancerVisitorFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaEnhancerVisitorFactory.java?rev=606484&r1=606483&r2=606484&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaEnhancerVisitorFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaEnhancerVisitorFactory.java Sat Dec 22 12:14:39 2007
@@ -20,7 +20,7 @@
 
 import org.apache.cayenne.enhancer.EmbeddableVisitor;
 import org.apache.cayenne.enhancer.EnhancerVisitorFactory;
-import org.apache.cayenne.enhancer.PersistentInterfaceVisitor;
+import org.apache.cayenne.enhancer.PojoVisitor;
 import org.apache.cayenne.jpa.map.JpaEmbeddable;
 import org.apache.cayenne.jpa.map.JpaEntity;
 import org.apache.cayenne.jpa.map.JpaEntityMap;
@@ -28,9 +28,10 @@
 import org.objectweb.asm.commons.SerialVersionUIDAdder;
 
 /**
- * Class enhancer used for JPA.
+ * EnhancerVisitorFactory implementation based on JPA mapping.
  * 
  * @author Andrus Adamchik
+ * @since 3.0
  */
 public class JpaEnhancerVisitorFactory implements EnhancerVisitorFactory {
 
@@ -48,12 +49,11 @@
         if (entity != null) {
 
             // create enhancer chain
-            PersistentInterfaceVisitor e1 = new PersistentInterfaceVisitor(out);
+            PojoVisitor e1 = new JpaPojoVisitor(out, entity);
             JpaAccessorVisitor e2 = new JpaAccessorVisitor(e1, entity);
 
             // this ensures that both enhanced and original classes have compatible
-            // serialized
-            // format even if no serialVersionUID is defined by the user
+            // serialized format even if no serialVersionUID is defined by the user
             SerialVersionUIDAdder e3 = new SerialVersionUIDAdder(e2);
 
             return e3;
@@ -61,10 +61,9 @@
 
         JpaEmbeddable embeddable = entityMap.embeddableForClass(key);
         if (embeddable != null) {
+
             // create enhancer chain
             EmbeddableVisitor e1 = new EmbeddableVisitor(out);
-
-            // TODO: andrus 12/16/2007 - setter visitor...
 
             // this ensures that both enhanced and original classes have compatible
             // serialized

Added: cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaPojoVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaPojoVisitor.java?rev=606484&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaPojoVisitor.java (added)
+++ cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/enhancer/JpaPojoVisitor.java Sat Dec 22 12:14:39 2007
@@ -0,0 +1,44 @@
+/*****************************************************************
+ *   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
+ *
+ *    http://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.jpa.enhancer;
+
+import java.util.Collection;
+
+import org.apache.cayenne.enhancer.PojoVisitor;
+import org.apache.cayenne.jpa.map.JpaManagedClass;
+import org.objectweb.asm.ClassVisitor;
+
+/**
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+class JpaPojoVisitor extends PojoVisitor {
+
+    protected JpaManagedClass managedClass;
+
+    JpaPojoVisitor(ClassVisitor visitor, JpaManagedClass managedClass) {
+        super(visitor);
+        this.managedClass = managedClass;
+    }
+
+    @Override
+    protected Collection<String> getLazilyFaultedProperties() {
+        return managedClass.getAttributes().getLazyAttributeNames();
+    }
+}

Modified: cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/map/JpaAttributes.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/map/JpaAttributes.java?rev=606484&r1=606483&r2=606484&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/map/JpaAttributes.java (original)
+++ cayenne/main/trunk/framework/cayenne-jpa-unpublished/src/main/java/org/apache/cayenne/jpa/map/JpaAttributes.java Sat Dec 22 12:14:39 2007
@@ -21,6 +21,8 @@
 import java.util.ArrayList;
 import java.util.Collection;
 
+import javax.persistence.FetchType;
+
 import org.apache.cayenne.util.TreeNodeChild;
 import org.apache.cayenne.util.XMLEncoder;
 import org.apache.cayenne.util.XMLSerializable;
@@ -94,6 +96,52 @@
 
         encoder.indent(-1);
         encoder.println("</attributes>");
+    }
+
+    /**
+     * Returns the names of attributes that are fetched lazily.
+     */
+    public Collection<String> getLazyAttributeNames() {
+        Collection<String> lazyAttributes = new ArrayList<String>();
+
+        if (basicAttributes != null) {
+            for (JpaBasic attribute : basicAttributes) {
+                if (attribute.getFetch() == FetchType.LAZY) {
+                    lazyAttributes.add(attribute.getName());
+                }
+            }
+        }
+
+        // TODO: andrus 12/22/2007 - since Cayenne fetches all relationships lazily unless
+        // query specifies a prefetch, for now we'll treat all relationships as LAZY (even
+        // though JPA defines all one-to-one relationships as EAGER). To be JPA compliant
+        // we need to change that at some point...
+
+        if (oneToOneRelationships != null) {
+            for (JpaOneToOne attribute : oneToOneRelationships) {
+                lazyAttributes.add(attribute.getName());
+            }
+        }
+
+        if (oneToManyRelationships != null) {
+            for (JpaOneToMany attribute : oneToManyRelationships) {
+                lazyAttributes.add(attribute.getName());
+            }
+        }
+
+        if (manyToOneRelationships != null) {
+            for (JpaManyToOne attribute : manyToOneRelationships) {
+                lazyAttributes.add(attribute.getName());
+            }
+        }
+
+        if (manyToManyRelationships != null) {
+            for (JpaManyToMany attribute : manyToManyRelationships) {
+                lazyAttributes.add(attribute.getName());
+            }
+        }
+
+        return lazyAttributes;
     }
 
     public JpaAttribute getAttribute(String name) {