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 2006/04/28 23:27:36 UTC

svn commit: r398019 [1/2] - in /incubator/cayenne/trunk/cayenne-jpa/src: main/java/org/apache/cayenne/jpa/bridge/ main/java/org/apache/cayenne/jpa/conf/ main/java/org/apache/cayenne/jpa/map/ test/java/org/apache/cayenne/jpa/bridge/ test/java/org/apache...

Author: aadamchik
Date: Fri Apr 28 14:27:32 2006
New Revision: 398019

URL: http://svn.apache.org/viewcvs?rev=398019&view=rev
Log:
more DataMap converter stuff

Added:
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorStack.java
      - copied, changed from r397948, incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorContext.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationPrototypes.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapDefaultsLoader.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoaderContext.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/JpaClassDescriptor.java
    incubator/cayenne/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/conf/JpaClassDescriptorTest.java
    incubator/cayenne/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/map/JpaTableTest.java
Removed:
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorContext.java
Modified:
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/bridge/DataMapConverter.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessor.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorFactory.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/ClassAnnotationProcessorFactory.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityCallbackAnnotationProcessorFactory.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapAnnotationLoader.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoader.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaAbstractEntity.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaEntityMap.java
    incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaTable.java
    incubator/cayenne/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/bridge/DataMapConverterTest.java
    incubator/cayenne/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/bridge/DataMapMappingAssertion.java
    incubator/cayenne/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/conf/EntityMapAnnotationLoaderTest.java
    incubator/cayenne/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/entity/cayenne/MockCayenneEntity1.java
    incubator/cayenne/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/entity/cayenne/MockCayenneEntity2.java

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/bridge/DataMapConverter.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/bridge/DataMapConverter.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/bridge/DataMapConverter.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/bridge/DataMapConverter.java Fri Apr 28 14:27:32 2006
@@ -21,6 +21,7 @@
 import org.apache.cayenne.jpa.JpaProviderException;
 import org.apache.cayenne.jpa.map.AccessType;
 import org.apache.cayenne.jpa.map.JpaAttribute;
+import org.apache.cayenne.jpa.map.JpaColumn;
 import org.apache.cayenne.jpa.map.JpaEntity;
 import org.apache.cayenne.jpa.map.JpaEntityMap;
 import org.apache.cayenne.jpa.map.JpaNamedQuery;
@@ -29,7 +30,9 @@
 import org.apache.cayenne.util.BaseTreeVisitor;
 import org.apache.cayenne.util.HierarchicalTreeVisitor;
 import org.apache.cayenne.util.TraversalUtil;
+import org.objectstyle.cayenne.dba.TypesMapping;
 import org.objectstyle.cayenne.map.DataMap;
+import org.objectstyle.cayenne.map.DbAttribute;
 import org.objectstyle.cayenne.map.DbEntity;
 import org.objectstyle.cayenne.map.ObjAttribute;
 import org.objectstyle.cayenne.map.ObjEntity;
@@ -60,12 +63,12 @@
         return conflicts;
     }
 
-    public synchronized DataMap toDataMap(String name, JpaEntityMap info) {
+    public synchronized DataMap toDataMap(String name, JpaEntityMap jpaMap) {
 
         // reset
         DataMap dataMap = new DataMap(name);
-        dataMap.setDefaultPackage(info.getPackageName());
-        dataMap.setDefaultSchema(info.getSchema());
+        dataMap.setDefaultPackage(jpaMap.getPackageName());
+        dataMap.setDefaultSchema(jpaMap.getSchema());
 
         this.targetPath = new ProjectPath(dataMap);
 
@@ -73,7 +76,7 @@
             visitor = createVisitor();
         }
 
-        TraversalUtil.traverse(info, visitor);
+        TraversalUtil.traverse(jpaMap, visitor);
         return dataMap;
     }
 
@@ -94,6 +97,38 @@
 
     class JpaAttributeVisitor extends NestedVisitor {
 
+        JpaAttributeVisitor() {
+            addChildVisitor(JpaColumn.class, new JpaColumnVisitor());
+        }
+
+        @Override
+        Object createObject(ProjectPath path) {
+
+            JpaAttribute jpaAttribute = (JpaAttribute) path.getObject();
+
+            ObjEntity parentCayenneEntity = (ObjEntity) targetPath.getObject();
+
+            if (jpaAttribute.isTransient()) {
+                return null;
+            }
+            else if (jpaAttribute.isRelationship()) {
+                ObjRelationship cayenneRelationship = new ObjRelationship(jpaAttribute
+                        .getName());
+
+                parentCayenneEntity.addRelationship(cayenneRelationship);
+                return cayenneRelationship;
+            }
+            else {
+                ObjAttribute cayenneAttribute = new ObjAttribute(jpaAttribute.getName());
+                cayenneAttribute.setType(getAttributeType(path, jpaAttribute.getName())
+                        .getName());
+                cayenneAttribute.setDbAttributeName(jpaAttribute.getColumn().getName());
+
+                parentCayenneEntity.addAttribute(cayenneAttribute);
+                return cayenneAttribute;
+            }
+        }
+
         Class getAttributeType(ProjectPath path, String name) {
             AccessType access = ((JpaEntityMap) path.getRoot()).getAccess();
 
@@ -133,40 +168,52 @@
                 return lookupFieldInHierarchy(superClass, fieldName);
             }
         }
+    }
+
+    class JpaColumnVisitor extends BaseTreeVisitor {
 
         @Override
-        Object createObject(ProjectPath path) {
+        public boolean onStartNode(ProjectPath path) {
+            JpaColumn jpaColumn = (JpaColumn) path.getObject();
 
-            JpaAttribute jpaAttribute = (JpaAttribute) path.getObject();
+            ObjAttribute cayenneObjAttribute = (ObjAttribute) targetPath.getObject();
 
-            ObjEntity parentCayenneEntity = (ObjEntity) targetPath.getObject();
+            DbAttribute dbAttribute = new DbAttribute(jpaColumn.getName());
 
-            if (jpaAttribute.isTransient()) {
+            // TODO, andrus, 4/28/2006 - per JPA spec, is there a way to override the type
+            // doing conversion implicitly???
+            dbAttribute.setType(TypesMapping.getSqlTypeByJava(cayenneObjAttribute
+                    .getJavaClass()));
 
+            dbAttribute.setMandatory(!jpaColumn.isNullable());
+
+            // TODO, andrus, 4/28/2006 - note that Cayenne DbAttribute's preceision is
+            // really scale (and precision is not defined at all). Fix this in
+            // DbAttribute.
+            dbAttribute.setPrecision(jpaColumn.getScale());
+
+            if (jpaColumn.getTable() == null) {
+                throw new JpaProviderException("No default table defined for JpaColumn "
+                        + jpaColumn.getName());
             }
-            else if (jpaAttribute.isRelationship()) {
-                ObjRelationship cayenneRelationship = new ObjRelationship(jpaAttribute
-                        .getName());
-                
-                parentCayenneEntity.addRelationship(cayenneRelationship);
-                return cayenneRelationship;
-            }
-            else {
-                ObjAttribute cayenneAttribute = new ObjAttribute(jpaAttribute.getName());
-                cayenneAttribute.setType(getAttributeType(path, jpaAttribute.getName())
-                        .getName());
 
-                parentCayenneEntity.addAttribute(cayenneAttribute);
-                return cayenneAttribute;
+            DbEntity entity = ((DataMap) targetPath.firstInstanceOf(DataMap.class))
+                    .getDbEntity(jpaColumn.getTable());
+
+            if (entity == null) {
+                throw new JpaProviderException("No DbEntity defined for table  "
+                        + jpaColumn.getTable());
             }
 
-            return null;
+            entity.addAttribute(dbAttribute);
+
+            return false;
         }
     }
 
     class JpaEntityVisitor extends NestedVisitor {
 
-        public JpaEntityVisitor() {
+        JpaEntityVisitor() {
             addChildVisitor(JpaAttribute.class, new JpaAttributeVisitor());
             addChildVisitor(JpaTable.class, new JpaTableVisitor());
         }
@@ -231,10 +278,6 @@
     }
 
     class JpaTableVisitor extends NestedVisitor {
-
-        public JpaTableVisitor() {
-
-        }
 
         @Override
         Object createObject(ProjectPath path) {

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessor.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessor.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessor.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessor.java Fri Apr 28 14:27:32 2006
@@ -28,11 +28,11 @@
      * Invoked in the beginning of the annotation tree traversal, which is done in a
      * depth-first manner.
      */
-    void onStartElement(AnnotatedElement element, AnnotationProcessorContext context);
+    void onStartElement(AnnotatedElement element, AnnotationProcessorStack context);
 
     /**
      * Invoked at the end of the annotation tree traversal, which is done in a depth-first
      * manner.
      */
-    void onFinishElement(AnnotatedElement element, AnnotationProcessorContext context);
+    void onFinishElement(AnnotatedElement element, AnnotationProcessorStack context);
 }

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorFactory.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorFactory.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorFactory.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorFactory.java Fri Apr 28 14:27:32 2006
@@ -36,12 +36,12 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
         }
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
         }
     };
 

Copied: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorStack.java (from r397948, incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorContext.java)
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorStack.java?p2=incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorStack.java&p1=incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorContext.java&r1=397948&r2=398019&rev=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorContext.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationProcessorStack.java Fri Apr 28 14:27:32 2006
@@ -23,7 +23,12 @@
  * 
  * @author Andrus Adamchik
  */
-public interface AnnotationProcessorContext {
+public interface AnnotationProcessorStack {
+
+    /**
+     * Returns parent context.
+     */
+    EntityMapLoaderContext getContext();
 
     void push(Object object);
 
@@ -32,4 +37,6 @@
     Object peek();
 
     void recordConflict(AnnotatedElement element, Class annotatedType, String message);
+    
+    int depth();
 }

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationPrototypes.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationPrototypes.java?rev=398019&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationPrototypes.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/AnnotationPrototypes.java Fri Apr 28 14:27:32 2006
@@ -0,0 +1,59 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation
+ *
+ *  Licensed 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.conf;
+
+import javax.persistence.Column;
+import javax.persistence.Table;
+
+import org.apache.cayenne.jpa.JpaProviderException;
+
+/**
+ * A utility class that provides access to default JPA annotation instances.
+ * 
+ * @author Andrus Adamchik
+ */
+@Table
+abstract class AnnotationPrototypes {
+
+    static final Column column;
+    static final Table table;
+
+    static {
+
+        table = AnnotationPrototypes.class.getAnnotation(Table.class);
+
+        try {
+            column = AnnotationPrototypes.class
+                    .getDeclaredField("annotatedColumn")
+                    .getAnnotation(Column.class);
+
+        }
+        catch (NoSuchFieldException e) {
+            throw new JpaProviderException("No annotated field found", e);
+        }
+    }
+
+    @Column
+    Object annotatedColumn;
+
+    public static Column getColumn() {
+        return column;
+    }
+
+    public static Table getTable() {
+        return table;
+    }
+}

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/ClassAnnotationProcessorFactory.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/ClassAnnotationProcessorFactory.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/ClassAnnotationProcessorFactory.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/ClassAnnotationProcessorFactory.java Fri Apr 28 14:27:32 2006
@@ -68,20 +68,13 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             Entity entityAnnotation = element.getAnnotation(Entity.class);
 
             JpaEntity entity = new JpaEntity();
             entity.setClassName(((Class) element).getName());
 
-            if (Util.isEmptyString(entityAnnotation.name())) {
-
-                // per JPA spec use unqualified class name
-                String fqName = ((Class) element).getName();
-                int split = fqName.lastIndexOf('.');
-                entity.setName(split > 0 ? fqName.substring(split + 1) : fqName);
-            }
-            else {
+            if (!Util.isEmptyString(entityAnnotation.name())) {
                 entity.setName(entityAnnotation.name());
             }
 
@@ -90,7 +83,7 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             JpaEntity entity = (JpaEntity) context.pop();
             JpaEntityMap entityMap = (JpaEntityMap) context.peek();
             entityMap.getEntities().add(entity);
@@ -101,7 +94,7 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             JpaEmbeddable embeddable = new JpaEmbeddable();
             embeddable.setClassName(((Class) element).getName());
@@ -110,7 +103,7 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             JpaEmbeddable embeddable = (JpaEmbeddable) context.pop();
             JpaEntityMap entityMap = (JpaEntityMap) context.peek();
             entityMap.getEmbeddables().add(embeddable);
@@ -121,7 +114,7 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             JpaMappedSuperclass superclass = new JpaMappedSuperclass();
             superclass.setClassName(((Class) element).getName());
@@ -130,7 +123,7 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             JpaMappedSuperclass superclass = (JpaMappedSuperclass) context.pop();
             JpaEntityMap entityMap = (JpaEntityMap) context.peek();
             entityMap.getMappedSuperclasses().add(superclass);
@@ -145,7 +138,7 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             Object parent = context.peek();
 
@@ -168,28 +161,28 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             // noop
         }
 
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
         void onMappedSuperclass(
                 JpaMappedSuperclass superclass,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
         void onEmbeddable(
                 JpaEmbeddable embeddable,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
@@ -198,13 +191,13 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
         void recordUnsupportedAnnotation(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             context.recordConflict(element, AnnotationProcessorFactory
                     .annotationClass(getClass()), "Unsupported in this place");
         }
@@ -216,7 +209,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             AttributeOverride annotation = element.getAnnotation(AttributeOverride.class);
             entity.getAttributeOverrides().add(new JpaAttributeOverride(annotation));
@@ -229,7 +222,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             AttributeOverrides annotation = element
                     .getAnnotation(AttributeOverrides.class);
@@ -246,7 +239,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             DiscriminatorColumn annotation = element
                     .getAnnotation(DiscriminatorColumn.class);
@@ -260,7 +253,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             DiscriminatorValue annotation = element
                     .getAnnotation(DiscriminatorValue.class);
@@ -276,7 +269,7 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             EntityListeners annotation = element.getAnnotation(EntityListeners.class);
 
@@ -305,7 +298,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             EntityListeners annotation = element.getAnnotation(EntityListeners.class);
 
@@ -334,7 +327,7 @@
         void onMappedSuperclass(
                 JpaMappedSuperclass superclass,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             EntityListeners annotation = element.getAnnotation(EntityListeners.class);
 
@@ -363,7 +356,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             entity.setExcludeDefaultListeners(true);
         }
@@ -372,7 +365,7 @@
         void onMappedSuperclass(
                 JpaMappedSuperclass superclass,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             superclass.setExcludeDefaultListeners(true);
         }
     }
@@ -383,7 +376,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             entity.setExcludeSuperclassListeners(true);
         }
@@ -392,7 +385,7 @@
         void onMappedSuperclass(
                 JpaMappedSuperclass superclass,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             superclass.setExcludeSuperclassListeners(true);
         }
     }
@@ -403,7 +396,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             IdClass annotation = element.getAnnotation(IdClass.class);
             entity.setIdClassName(annotation.value().getName());
@@ -413,7 +406,7 @@
         void onMappedSuperclass(
                 JpaMappedSuperclass superclass,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             IdClass annotation = element.getAnnotation(IdClass.class);
             superclass.setIdClassName(annotation.value().getName());
         }
@@ -425,7 +418,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             Inheritance annotation = element.getAnnotation(Inheritance.class);
             entity.setInheritance(new JpaInheritance(annotation));
@@ -438,7 +431,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedNativeQueries annotation = element
                     .getAnnotation(NamedNativeQueries.class);
@@ -452,7 +445,7 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedNativeQueries annotation = element
                     .getAnnotation(NamedNativeQueries.class);
@@ -469,7 +462,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedNativeQuery annotation = element.getAnnotation(NamedNativeQuery.class);
             entity.getNamedNativeQueries().add(new JpaNamedNativeQuery(annotation));
@@ -479,7 +472,7 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedNativeQuery annotation = element.getAnnotation(NamedNativeQuery.class);
             entityMap.getNamedNativeQueries().add(new JpaNamedNativeQuery(annotation));
@@ -492,7 +485,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedQueries annotation = element.getAnnotation(NamedQueries.class);
             for (int i = 0; i < annotation.value().length; i++) {
@@ -504,7 +497,7 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedQueries annotation = element.getAnnotation(NamedQueries.class);
             for (int i = 0; i < annotation.value().length; i++) {
@@ -519,7 +512,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedQuery annotation = element.getAnnotation(NamedQuery.class);
             entity.getNamedQueries().add(new JpaNamedQuery(annotation));
@@ -529,7 +522,7 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             NamedQuery annotation = element.getAnnotation(NamedQuery.class);
             entityMap.getNamedQueries().add(new JpaNamedQuery(annotation));
@@ -542,7 +535,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             PrimaryKeyJoinColumn annotation = element
                     .getAnnotation(PrimaryKeyJoinColumn.class);
@@ -558,7 +551,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             PrimaryKeyJoinColumns annotation = element
                     .getAnnotation(PrimaryKeyJoinColumns.class);
@@ -575,7 +568,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             SecondaryTable annotation = element.getAnnotation(SecondaryTable.class);
             entity.getSecondaryTables().add(new JpaSecondaryTable(annotation));
@@ -588,7 +581,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             SecondaryTables annotation = element.getAnnotation(SecondaryTables.class);
             for (int i = 0; i < annotation.value().length; i++) {
@@ -604,7 +597,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             SequenceGenerator annotation = element.getAnnotation(SequenceGenerator.class);
             entity.setSequenceGenerator(new JpaSequenceGenerator(annotation));
@@ -614,7 +607,7 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             SequenceGenerator annotation = element.getAnnotation(SequenceGenerator.class);
             entityMap.getSequenceGenerators().add(new JpaSequenceGenerator(annotation));
@@ -627,7 +620,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             SqlResultSetMapping annotation = element
                     .getAnnotation(SqlResultSetMapping.class);
@@ -638,7 +631,7 @@
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             SqlResultSetMapping annotation = element
                     .getAnnotation(SqlResultSetMapping.class);
@@ -653,17 +646,17 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             TableGenerator annotation = element.getAnnotation(TableGenerator.class);
             entity.setTableGenerator(new JpaTableGenerator(annotation));
         }
-        
+
         @Override
         void onEntityMap(
                 JpaEntityMap entityMap,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             TableGenerator annotation = element.getAnnotation(TableGenerator.class);
             entityMap.getTableGenerators().add(new JpaTableGenerator(annotation));
@@ -676,7 +669,7 @@
         void onEntity(
                 JpaEntity entity,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             Table annotation = element.getAnnotation(Table.class);
             entity.setTable(new JpaTable(annotation));

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityCallbackAnnotationProcessorFactory.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityCallbackAnnotationProcessorFactory.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityCallbackAnnotationProcessorFactory.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityCallbackAnnotationProcessorFactory.java Fri Apr 28 14:27:32 2006
@@ -28,7 +28,7 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             Method m = (Method) element;
             updateEntity((JpaAbstractEntity) context.peek(), new JpaLifecycleCallback(m
@@ -37,7 +37,7 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             // noop...
         }
 

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapAnnotationLoader.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapAnnotationLoader.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapAnnotationLoader.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapAnnotationLoader.java Fri Apr 28 14:27:32 2006
@@ -25,10 +25,7 @@
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import javax.persistence.Embeddable;
 import javax.persistence.EmbeddedId;
@@ -48,12 +45,10 @@
 import org.apache.cayenne.jpa.map.JpaAbstractEntity;
 import org.apache.cayenne.jpa.map.JpaEntityMap;
 import org.objectstyle.cayenne.util.Util;
-import org.objectstyle.cayenne.validation.SimpleValidationFailure;
-import org.objectstyle.cayenne.validation.ValidationResult;
 
 /**
- * {@link org.apache.cayenne.jpa.map.JpaEntityMap} loader that reads mapping
- * information from the class annotations per JPA specification.
+ * {@link org.apache.cayenne.jpa.map.JpaEntityMap} loader that reads mapping information
+ * from the class annotations per JPA specification.
  * <h3>Specification Documentation, persistence_1_0.xsd, "class" element.</h3>
  * <p>
  * [Each managed class] should be annotated with either \@Entity, \@Embeddable or
@@ -65,14 +60,9 @@
 
     static final Map<String, Integer> TYPE_ANNOTATION_ORDERING_WEIGHTS;
     static final Map<String, Integer> MEMBER_ANNOTATION_ORDERING_WEIGHTS;
-    static final Pattern GETTER_PATTERN;
-    static final Pattern SETTER_PATTERN;
 
     static {
 
-        GETTER_PATTERN = Pattern.compile("^(is|get)([A-Z].*)$");
-        SETTER_PATTERN = Pattern.compile("^set([A-Z].*)$");
-
         TYPE_ANNOTATION_ORDERING_WEIGHTS = new HashMap<String, Integer>();
 
         // annotations that are top-level only
@@ -99,7 +89,8 @@
         // 'attribute' is implied...
     }
 
-    protected ValidationResult conflicts;
+    protected EntityMapLoaderContext context;
+
     protected Comparator<Annotation> typeAnnotationsSorter;
     protected Comparator<Annotation> memberAnnotationsSorter;
 
@@ -107,8 +98,8 @@
     protected AnnotationProcessorFactory memberProcessorFactory;
     protected AnnotationProcessorFactory callbackProcessorFactory;
 
-    public EntityMapAnnotationLoader(ValidationResult conflicts) {
-        this.conflicts = conflicts;
+    public EntityMapAnnotationLoader(EntityMapLoaderContext context) {
+        this.context = context;
         this.typeAnnotationsSorter = new AnnotationSorter(
                 TYPE_ANNOTATION_ORDERING_WEIGHTS);
         this.memberAnnotationsSorter = new AnnotationSorter(
@@ -131,27 +122,27 @@
         // per 'getAnnotations' docs, array is returned by copy, so we can modify it...
         Arrays.sort(classAnnotations, typeAnnotationsSorter);
 
-        Context context = new Context();
-        context.push(entityMap);
+        AnnotationProcessorStack stack = context.createAnnotationProcessorContext();
+        stack.push(entityMap);
 
         // === push class-level stuff
         for (int i = 0; i < classAnnotations.length; i++) {
             AnnotationProcessor processor = classProcessorFactory
                     .getProcessor(classAnnotations[i]);
             if (processor != null) {
-                processor.onStartElement(managedClass, context);
+                processor.onStartElement(managedClass, stack);
             }
         }
 
         // if class is not properly annotated, bail early
-        if (context.stack.size() == 1) {
+        if (stack.depth() == 1) {
             return;
         }
 
         // apply entity callbacks ...
-        if (context.peek() instanceof JpaAbstractEntity) {
+        if (stack.peek() instanceof JpaAbstractEntity) {
             for (Method callback : getEntityCallbacks(managedClass)) {
-                applyEntityCallbackAnnotations(callback, context);
+                applyEntityCallbackAnnotations(callback, stack);
             }
         }
 
@@ -165,37 +156,13 @@
         // we still must determine the access type to apply default mappping rules. How?
         // (using FIELD access for now).
 
-        // === process field annotations
-
-        // JPA Spec, 2.1.9.3, regarding non-entity superclasses:
-
-        // The non-entity superclass serves for inheritance of behavior only. The state of
-        // a non-entity superclass is not persistent. Any state inherited fromnon-entity
-        // superclasses is non-persistent in an inheriting entity class. This
-        // non-persistent state is not managed by the EntityManager, nor it is
-        // required to be retained across transactions. Any annotations on such
-        // superclasses are ignored.
-
-        Field[] fields = managedClass.getDeclaredFields();
-        for (int i = 0; i < fields.length; i++) {
-
-            // skip transient fields (in a Java sense)
-            if (Modifier.isTransient(fields[i].getModifiers())) {
-                continue;
-            }
-
-            applyMemberAnnotations(fields[i], context);
+        JpaClassDescriptor descriptor = this.context.getDescriptor(managedClass);
+        for (Field field : descriptor.getPersistentFieldCandidates()) {
+            applyMemberAnnotations(field, stack);
         }
 
-        // == process getter annotations
-
-        // per JPA spec, 2.1.1:
-        // The property accessor methods must be public or protected. When
-        // property-based access is used, the object/relational mapping annotations for
-        // the entity class annotate the getter property accessors.
-
-        for (Method propertyGetter : getPropertyGetters(managedClass)) {
-            applyMemberAnnotations(propertyGetter, context);
+        for (Method propertyGetter : descriptor.getPersistentPropertyCandidates()) {
+            applyMemberAnnotations(propertyGetter, stack);
         }
 
         // === pop class-level stuff
@@ -203,14 +170,14 @@
             AnnotationProcessor processor = classProcessorFactory
                     .getProcessor(classAnnotations[i]);
             if (processor != null) {
-                processor.onFinishElement(managedClass, context);
+                processor.onFinishElement(managedClass, stack);
             }
         }
     }
 
     protected void applyMemberAnnotations(
             AnnotatedElement member,
-            AnnotationProcessorContext context) {
+            AnnotationProcessorStack stack) {
 
         Annotation[] annotations = member.getAnnotations();
         // per 'getAnnotations' docs, array is returned by copy, so we can modify it...
@@ -222,7 +189,7 @@
                     .getProcessor(annotations[j]);
 
             if (memberProcessor != null) {
-                memberProcessor.onStartElement(member, context);
+                memberProcessor.onStartElement(member, stack);
             }
         }
 
@@ -232,14 +199,14 @@
                     .getProcessor(annotations[j]);
 
             if (memberProcessor != null) {
-                memberProcessor.onFinishElement(member, context);
+                memberProcessor.onFinishElement(member, stack);
             }
         }
     }
 
     protected void applyEntityCallbackAnnotations(
             Method method,
-            AnnotationProcessorContext context) {
+            AnnotationProcessorStack stack) {
 
         Annotation[] annotations = method.getAnnotations();
 
@@ -249,7 +216,7 @@
                     .getProcessor(annotations[j]);
 
             if (callbackProcessor != null) {
-                callbackProcessor.onStartElement(method, context);
+                callbackProcessor.onStartElement(method, stack);
             }
         }
 
@@ -257,80 +224,6 @@
         // annotations...
     }
 
-    /**
-     * Returns getters for public and protected methods that look like read/write bean
-     * properties, as those are the methods to look for annotations.
-     */
-    protected Collection<Method> getPropertyGetters(Class managedClass) {
-
-        Map<String, PropertyTuple> properties = new HashMap<String, PropertyTuple>();
-
-        // JPA Spec, 2.1.9.3, regarding non-entity superclasses:
-
-        // The non-entity superclass serves for inheritance of behavior only. The state of
-        // a non-entity superclass is not persistent. Any state inherited fromnon-entity
-        // superclasses is non-persistent in an inheriting entity class. This
-        // non-persistent state is not managed by the EntityManager, nor it is
-        // required to be retained across transactions. Any annotations on such
-        // superclasses are ignored.
-
-        Method[] methods = managedClass.getDeclaredMethods();
-        for (int i = 0; i < methods.length; i++) {
-
-            int modifiers = methods[i].getModifiers();
-            if (!Modifier.isProtected(modifiers) && !Modifier.isPublic(modifiers)) {
-                continue;
-            }
-
-            String name = methods[i].getName();
-            Class[] parameters = methods[i].getParameterTypes();
-            Class returnType = methods[i].getReturnType();
-            boolean isVoid = Void.TYPE.equals(returnType);
-
-            if (!isVoid && parameters.length == 0) {
-                Matcher getMatch = GETTER_PATTERN.matcher(name);
-                if (getMatch.matches()) {
-
-                    String key = getMatch.group(2) + ":" + returnType.getName();
-                    PropertyTuple t = properties.get(key);
-                    if (t == null) {
-                        t = new PropertyTuple();
-                        properties.put(key, t);
-                    }
-
-                    t.getter = methods[i];
-                    continue;
-                }
-            }
-
-            if (isVoid && parameters.length == 1) {
-                Matcher setMatch = SETTER_PATTERN.matcher(name);
-                if (setMatch.matches()) {
-
-                    String key = setMatch.group(1) + ":" + parameters[0].getName();
-
-                    PropertyTuple t = properties.get(key);
-                    if (t == null) {
-                        t = new PropertyTuple();
-                        properties.put(key, t);
-                    }
-
-                    t.setter = methods[i];
-                }
-            }
-        }
-
-        Collection<Method> matchingMethods = new ArrayList<Method>(properties.size());
-
-        for (PropertyTuple t : properties.values()) {
-            if (t.getter != null && t.setter != null) {
-                matchingMethods.add(t.getter);
-            }
-        }
-
-        return matchingMethods;
-    }
-
     protected Collection<Method> getEntityCallbacks(Class managedClass) {
 
         Collection<Method> callbacks = new ArrayList<Method>(3);
@@ -380,43 +273,4 @@
         }
     }
 
-    final class PropertyTuple {
-
-        Method getter;
-        Method setter;
-    }
-
-    final class Context implements AnnotationProcessorContext {
-
-        LinkedList stack = new LinkedList();
-
-        public Object peek() {
-            return stack.peek();
-        }
-
-        public Object pop() {
-            return stack.removeFirst();
-        }
-
-        public void push(Object object) {
-            stack.addFirst(object);
-        }
-
-        public void recordConflict(
-                AnnotatedElement element,
-                Class annotatedType,
-                String message) {
-
-            StringBuilder buffer = new StringBuilder();
-            buffer.append("Problem processing annotation: ").append(
-                    annotatedType.getName());
-            buffer.append(", annotated element: ").append(element);
-
-            if (message != null) {
-                buffer.append(", details: ").append(message);
-            }
-
-            conflicts.addFailure(new SimpleValidationFailure(peek(), buffer.toString()));
-        }
-    }
 }

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapDefaultsLoader.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapDefaultsLoader.java?rev=398019&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapDefaultsLoader.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapDefaultsLoader.java Fri Apr 28 14:27:32 2006
@@ -0,0 +1,228 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation
+ *
+ *  Licensed 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.conf;
+
+import java.lang.reflect.Member;
+
+import org.apache.cayenne.jpa.JpaProviderException;
+import org.apache.cayenne.jpa.map.AccessType;
+import org.apache.cayenne.jpa.map.JpaAttribute;
+import org.apache.cayenne.jpa.map.JpaBasic;
+import org.apache.cayenne.jpa.map.JpaColumn;
+import org.apache.cayenne.jpa.map.JpaEntity;
+import org.apache.cayenne.jpa.map.JpaEntityMap;
+import org.apache.cayenne.jpa.map.JpaMappedSuperclass;
+import org.apache.cayenne.jpa.map.JpaTable;
+import org.apache.cayenne.util.BaseTreeVisitor;
+import org.apache.cayenne.util.HierarchicalTreeVisitor;
+import org.apache.cayenne.util.TraversalUtil;
+import org.objectstyle.cayenne.project.ProjectPath;
+
+/**
+ * Initializes JPA specification compatible mapping defaults.
+ * 
+ * @author Andrus Adamchik
+ */
+public class EntityMapDefaultsLoader {
+
+    protected HierarchicalTreeVisitor visitor;
+    protected EntityMapLoaderContext context;
+
+    public EntityMapDefaultsLoader(EntityMapLoaderContext context) {
+        this.context = context;
+    }
+
+    public void loadDefaults(JpaEntityMap entityMap) throws JpaProviderException {
+
+        if (visitor == null) {
+            visitor = createVisitor();
+        }
+
+        TraversalUtil.traverse(entityMap, visitor);
+    }
+
+    /**
+     * Creates a stateless instance of the JpaEntityMap traversal visitor. This method is
+     * lazily invoked and cached by this object.
+     */
+    protected HierarchicalTreeVisitor createVisitor() {
+        return new EntityMapVisitor();
+    }
+
+    abstract class AbstractEntityVisitor extends BaseTreeVisitor {
+
+        AbstractEntityVisitor() {
+            addChildVisitor(JpaAttribute.class, new AttributeVisitor());
+        }
+
+        @Override
+        public boolean onStartNode(ProjectPath path) {
+            JpaEntity entity = (JpaEntity) path.getObject();
+
+            // * entity name
+            if (entity.getClassName() == null) {
+                return false;
+            }
+
+            if (entity.getName() == null) {
+
+                // use unqualified class name
+                String fqName = entity.getClassName();
+                int split = fqName.lastIndexOf('.');
+                entity.setName(split > 0 ? fqName.substring(split + 1) : fqName);
+            }
+
+            // * default persistent fields
+            JpaClassDescriptor descriptor = context.getLoadedDescriptor(entity
+                    .getClassName());
+
+            if (descriptor == null) {
+                return false;
+            }
+
+            JpaEntityMap root = (JpaEntityMap) path.getRoot();
+            if (root.getAccess() == AccessType.FIELD) {
+                for (Member candidate : descriptor.getPersistentFieldCandidates()) {
+                    processCandidate(entity, descriptor, candidate);
+                }
+            }
+            else {
+                for (Member candidate : descriptor.getPersistentPropertyCandidates()) {
+                    processCandidate(entity, descriptor, candidate);
+                }
+            }
+
+            // * default table (see @Table annotation defaults, JPA spec 9.1.1)
+            if (entity.getTable() == null) {
+                JpaTable table = new JpaTable(AnnotationPrototypes.getTable());
+                table.setName(entity.getName());
+            }
+
+            return true;
+        }
+
+        void processCandidate(
+                JpaEntity entity,
+                JpaClassDescriptor descriptor,
+                Member candidate) {
+
+            String key = descriptor.getPersistentCandidateName(candidate);
+
+            // this shouldn't actually happen...
+            if (key == null) {
+                return;
+            }
+
+            if (entity.attributeForName(key) != null) {
+                return;
+            }
+
+            // JPA Spec, 2.1.6:
+            // If the type of the field or property is one of the following, it is mapped
+            // in the same way as it would if it were annotated as Basic: Java primitive
+            // types, wrappers of the primitive types, java.lang.String,
+            // java.math.BigInteger, java.math.BigDecimal, java.util.Date,
+            // java.util.Calendar, java.sql.Date, java.sql.Time,
+            // java.sql.Timestamp, byte[], Byte[], char[], Character[], enums, any other
+            // type that implements Serializable. See Sections 9.1.16 through 9.1.19.
+            // It is an error if no annotation is present and none of the above rules
+            // apply.
+
+            // TODO: andrus, 4/28/2006 check attribute type per comment above..
+
+            JpaAttribute attribute = new JpaAttribute();
+            attribute.setBasic(new JpaBasic());
+            attribute.setName(key);
+            entity.getAttributes().add(attribute);
+        }
+    }
+
+    final class AttributeVisitor extends BaseTreeVisitor {
+
+        AttributeVisitor() {
+            addChildVisitor(JpaColumn.class, new ColumnVisitor());
+        }
+
+        @Override
+        public boolean onStartNode(ProjectPath path) {
+            JpaAttribute attribute = (JpaAttribute) path.getObject();
+
+            if (attribute.isRelationship()) {
+
+            }
+            else if (attribute.isTransient()) {
+                return false;
+            }
+            else {
+                if (attribute.getColumn() == null) {
+                    JpaColumn column = new JpaColumn(AnnotationPrototypes.getColumn());
+                    column.setName(attribute.getName());
+                    attribute.setColumn(column);
+                }
+            }
+
+            return true;
+        }
+    }
+
+    final class ColumnVisitor extends BaseTreeVisitor {
+
+        @Override
+        public boolean onStartNode(ProjectPath path) {
+            JpaColumn column = (JpaColumn) path.getObject();
+            
+            if(column.getName() == null) {
+                JpaAttribute attribute = (JpaAttribute) path.firstInstanceOf(JpaAttribute.class);
+                column.setName(attribute.getName());
+            }
+
+            if(column.getTable() == null) {
+                JpaEntity entity = (JpaEntity) path.firstInstanceOf(JpaEntity.class);
+                column.setTable(entity.getTable().getName());
+            }
+             
+            return true;
+        }
+    }
+
+    final class EntityMapVisitor extends BaseTreeVisitor {
+
+        EntityMapVisitor() {
+            addChildVisitor(JpaEntity.class, new EntityVisitor());
+            addChildVisitor(JpaMappedSuperclass.class, new MappedSuperclassVisitor());
+        }
+
+        @Override
+        public boolean onStartNode(ProjectPath path) {
+            JpaEntityMap entityMap = (JpaEntityMap) path.getObject();
+
+            // TODO: andrus, 4/28/2006 - actually we need to analyze preloaded classes and
+            // see how they were annotated to choose the right access type...
+
+            entityMap.setAccess(AccessType.FIELD);
+
+            return true;
+        }
+    }
+
+    final class EntityVisitor extends AbstractEntityVisitor {
+
+    }
+
+    final class MappedSuperclassVisitor extends AbstractEntityVisitor {
+
+    }
+}

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoader.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoader.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoader.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoader.java Fri Apr 28 14:27:32 2006
@@ -19,14 +19,13 @@
 import java.net.URL;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 import javax.persistence.spi.PersistenceUnitInfo;
 
 import org.apache.cayenne.jpa.JpaProviderException;
 import org.apache.cayenne.jpa.map.JpaEntityMap;
-import org.objectstyle.cayenne.validation.ValidationFailure;
-import org.objectstyle.cayenne.validation.ValidationResult;
 
 /**
  * Loads JPA mapping information from all sources per JPA specification.
@@ -39,8 +38,8 @@
  * <li>One or more jar files that will be searched for classes
  * <li>An explicit list of the classes
  * <li>The annotated managed persistence classes contained in the root of the persistence
- * unit (unless theexclude-unlisted-classes element is specified) [Java SE doesn't have to
- * support that].
+ * unit (unless the exclude-unlisted-classes element is specified) [Java SE doesn't have
+ * to support that].
  * </ul>
  * <p>
  * The result is undefined if multiple mapping files (including any orm.xml file)
@@ -63,14 +62,15 @@
     static final String DESCRIPTOR_LOCATION = "META-INF/orm.xml";
 
     protected JpaEntityMap entityMap;
-    protected ValidationResult conflicts;
+    protected EntityMapLoaderContext context;
+    protected Map<String, JpaClassDescriptor> descriptors;
 
     /**
      * Creates an EntityMapLoader for the persistence unit, merging entity information
      * from all locations supported by the JPA specification.
      */
     public EntityMapLoader(PersistenceUnitInfo persistenceUnit) {
-        this.conflicts = new ValidationResult();
+        this.context = new EntityMapLoaderContext();
         this.entityMap = loadEntityMap(persistenceUnit);
     }
 
@@ -82,13 +82,6 @@
     }
 
     /**
-     * Returns a descriptor of conflicts encountered during load.
-     */
-    public ValidationResult getConflicts() {
-        return conflicts;
-    }
-
-    /**
      * Loads a combined entity map including managed class descriptors from all supported
      * locations.
      */
@@ -106,6 +99,8 @@
             JpaEntityMap xmlMap = loadFromXML(persistenceUnit);
             JpaEntityMap baseMap = loadFromAnnotations(persistenceUnit);
             baseMap.mergeOverride(xmlMap);
+            new EntityMapDefaultsLoader(context).loadDefaults(baseMap);
+
             return baseMap;
         }
         catch (JpaProviderException e) {
@@ -163,9 +158,6 @@
                 }
             }
         }
-        
-        // 4. load defaults
-        // TODO: andrus, 4/21/2006 - implement default loading
 
         return map != null ? map : new JpaEntityMap();
     }
@@ -190,13 +182,7 @@
             return map;
         }
 
-        ValidationResult conflicts = baseMap.mergeNoOverride(map);
-        if (conflicts != null && conflicts.hasFailures()) {
-            for (Object failure : conflicts.getFailures()) {
-                this.conflicts.addFailure((ValidationFailure) failure);
-            }
-        }
-
+        baseMap.mergeNoOverride(map, context);
         return baseMap;
     }
 }

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoaderContext.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoaderContext.java?rev=398019&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoaderContext.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/EntityMapLoaderContext.java Fri Apr 28 14:27:32 2006
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation
+ *
+ *  Licensed 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.conf;
+
+import java.lang.reflect.AnnotatedElement;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.objectstyle.cayenne.validation.SimpleValidationFailure;
+import org.objectstyle.cayenne.validation.ValidationFailure;
+import org.objectstyle.cayenne.validation.ValidationResult;
+
+/**
+ * A common context shared by different loaders during JPA mapping information processing.
+ * 
+ * @author Andrus Adamchik
+ */
+public class EntityMapLoaderContext {
+
+    protected Map<String, JpaClassDescriptor> descriptors;
+    protected ValidationResult conflicts;
+
+    public EntityMapLoaderContext() {
+        this.conflicts = new ValidationResult();
+    }
+
+    public AnnotationProcessorStack createAnnotationProcessorContext() {
+        return new AnnotationContext();
+    }
+
+    /**
+     * Returns a previously laoded descriptor matching class name or null if no such
+     * descriptor was loaded.
+     */
+    public JpaClassDescriptor getLoadedDescriptor(String managedClassName) {
+        return (descriptors != null) ? descriptors.get(managedClassName) : null;
+    }
+
+    /**
+     * Returns a class descriptor for a given managed class, compiling it on the fly if
+     * needed.
+     */
+    public JpaClassDescriptor getDescriptor(Class managedClass) {
+        JpaClassDescriptor descriptor = null;
+        String name = managedClass.getName();
+
+        if (descriptors == null) {
+            descriptors = new HashMap<String, JpaClassDescriptor>();
+        }
+        else {
+            descriptor = descriptors.get(name);
+        }
+
+        if (descriptor == null) {
+            descriptor = new JpaClassDescriptor(managedClass);
+            descriptors.put(name, descriptor);
+        }
+
+        return descriptor;
+    }
+
+    public void recordConflict(ValidationFailure conflict) {
+        conflicts.addFailure(conflict);
+    }
+
+    public ValidationResult getConflicts() {
+        return conflicts;
+    }
+
+    final class AnnotationContext implements AnnotationProcessorStack {
+
+        LinkedList stack = new LinkedList();
+
+        public EntityMapLoaderContext getContext() {
+            return EntityMapLoaderContext.this;
+        }
+
+        public int depth() {
+            return stack.size();
+        }
+
+        public Object peek() {
+            return stack.peek();
+        }
+
+        public Object pop() {
+            return stack.removeFirst();
+        }
+
+        public void push(Object object) {
+            stack.addFirst(object);
+        }
+
+        public void recordConflict(
+                AnnotatedElement element,
+                Class annotatedType,
+                String message) {
+
+            StringBuilder buffer = new StringBuilder();
+            buffer.append("Problem processing annotation: ").append(
+                    annotatedType.getName());
+            buffer.append(", annotated element: ").append(element);
+
+            if (message != null) {
+                buffer.append(", details: ").append(message);
+            }
+
+            EntityMapLoaderContext.this.recordConflict(new SimpleValidationFailure(
+                    peek(),
+                    buffer.toString()));
+        }
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/JpaClassDescriptor.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/JpaClassDescriptor.java?rev=398019&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/JpaClassDescriptor.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/JpaClassDescriptor.java Fri Apr 28 14:27:32 2006
@@ -0,0 +1,195 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation
+ *
+ *  Licensed 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.conf;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Provides the JPA information about a class, such potential persistence fields, etc.
+ * 
+ * @author Andrus Adamchik
+ */
+public class JpaClassDescriptor {
+
+    static final Pattern GETTER_PATTERN = Pattern.compile("^(is|get)([A-Z].*)$");
+    static final Pattern SETTER_PATTERN = Pattern.compile("^set([A-Z].*)$");
+
+    protected Collection<Field> persistentFieldCandidates;
+    protected Collection<Method> persistentPropertyCandidates;
+    protected Class managedClass;
+
+    public JpaClassDescriptor(Class managedClass) {
+        this.managedClass = managedClass;
+    }
+
+    public Class getManagedClass() {
+        return managedClass;
+    }
+
+    /**
+     * Returns an abstract persistent attribute name for a given member. If this member
+     * does not correspond to a valid persistence attribute, returns null.
+     */
+    public String getPersistentCandidateName(Member member) {
+        if (member instanceof Field) {
+            return getPersistentFieldCandidates().contains(member) ? ((Field) member)
+                    .getName() : null;
+        }
+        else if (member instanceof Method) {
+            if (getPersistentPropertyCandidates().contains(member)) {
+                String name = ((Method) member).getName();
+                Matcher getterMatcher = GETTER_PATTERN.matcher(name);
+
+                if (getterMatcher.matches()) {
+                    return getterMatcher.group(2);
+                }
+                else {
+                    return null;
+                }
+            }
+            else {
+                return null;
+            }
+        }
+        else {
+            return null;
+        }
+    }
+
+    public Collection<Field> getPersistentFieldCandidates() {
+        if (persistentFieldCandidates == null) {
+            compileFieldCandidates();
+        }
+
+        return persistentFieldCandidates;
+    }
+
+    /**
+     * Returns getters for public and protected methods that look like read/write bean
+     * properties, as those are potential persistent properties.
+     */
+    public Collection<Method> getPersistentPropertyCandidates() {
+        if (persistentPropertyCandidates == null) {
+            compilePropertyCandidates();
+        }
+
+        return persistentPropertyCandidates;
+    }
+
+    protected void compileFieldCandidates() {
+
+        Field[] fields = managedClass.getDeclaredFields();
+        persistentFieldCandidates = new ArrayList<Field>(fields.length);
+
+        for (int i = 0; i < fields.length; i++) {
+
+            // skip transient fields (in a Java sense)
+            if (Modifier.isTransient(fields[i].getModifiers())) {
+                continue;
+            }
+
+            persistentFieldCandidates.add(fields[i]);
+        }
+    }
+
+    protected void compilePropertyCandidates() {
+
+        Map<String, PropertyTuple> properties = new HashMap<String, PropertyTuple>();
+
+        // per JPA spec, 2.1.1:
+        // The property accessor methods must be public or protected. When
+        // property-based access is used, the object/relational mapping annotations for
+        // the entity class annotate the getter property accessors.
+
+        // JPA Spec, 2.1.9.3, regarding non-entity superclasses:
+
+        // The non-entity superclass serves for inheritance of behavior only. The state of
+        // a non-entity superclass is not persistent. Any state inherited from non-entity
+        // superclasses is non-persistent in an inheriting entity class. This
+        // non-persistent state is not managed by the EntityManager, nor it is
+        // required to be retained across transactions. Any annotations on such
+        // superclasses are ignored.
+
+        Method[] methods = managedClass.getDeclaredMethods();
+        for (int i = 0; i < methods.length; i++) {
+
+            int modifiers = methods[i].getModifiers();
+            if (!Modifier.isProtected(modifiers) && !Modifier.isPublic(modifiers)) {
+                continue;
+            }
+
+            String name = methods[i].getName();
+            Class[] parameters = methods[i].getParameterTypes();
+            Class returnType = methods[i].getReturnType();
+            boolean isVoid = Void.TYPE.equals(returnType);
+
+            if (!isVoid && parameters.length == 0) {
+                Matcher getMatch = GETTER_PATTERN.matcher(name);
+                if (getMatch.matches()) {
+
+                    String key = getMatch.group(2) + ":" + returnType.getName();
+                    PropertyTuple t = properties.get(key);
+                    if (t == null) {
+                        t = new PropertyTuple();
+                        properties.put(key, t);
+                    }
+
+                    t.getter = methods[i];
+                    continue;
+                }
+            }
+
+            if (isVoid && parameters.length == 1) {
+                Matcher setMatch = SETTER_PATTERN.matcher(name);
+                if (setMatch.matches()) {
+
+                    String key = setMatch.group(1) + ":" + parameters[0].getName();
+
+                    PropertyTuple t = properties.get(key);
+                    if (t == null) {
+                        t = new PropertyTuple();
+                        properties.put(key, t);
+                    }
+
+                    t.setter = methods[i];
+                }
+            }
+        }
+
+        this.persistentPropertyCandidates = new ArrayList<Method>(properties.size());
+
+        for (PropertyTuple t : properties.values()) {
+            if (t.getter != null && t.setter != null) {
+                persistentPropertyCandidates.add(t.getter);
+            }
+        }
+    }
+
+    final class PropertyTuple {
+
+        Method getter;
+        Method setter;
+    }
+}

Modified: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java?rev=398019&r1=398018&r2=398019&view=diff
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java (original)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java Fri Apr 28 14:27:32 2006
@@ -16,9 +16,7 @@
 package org.apache.cayenne.jpa.conf;
 
 import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.regex.Matcher;
+import java.lang.reflect.Member;
 
 import javax.persistence.AttributeOverride;
 import javax.persistence.AttributeOverrides;
@@ -65,39 +63,36 @@
 
     static String getMemberName(
             AnnotatedElement element,
-            AnnotationProcessorContext context,
+            AnnotationProcessorStack context,
             Class annotatedType) {
 
-        if (element instanceof Field) {
-            return ((Field) element).getName();
-        }
-        else if (element instanceof Method) {
-
-            String name = ((Method) element).getName();
-            Matcher getterMatcher = EntityMapAnnotationLoader.GETTER_PATTERN
-                    .matcher(name);
+        String name = null;
 
-            if (getterMatcher.matches()) {
-                return getterMatcher.group(2);
-            }
-            else {
-                // TODO: andrus, 4/23/2006 - may need to check other getter properties
-                // to see if it is valid
+        if (element instanceof Member) {
+            Member member = (Member) element;
+            name = context
+                    .getContext()
+                    .getDescriptor(member.getDeclaringClass())
+                    .getPersistentCandidateName(member);
+            if (name == null) {
                 context.recordConflict(
                         element,
                         annotatedType,
                         "Annotated method is not a property getter: " + name);
             }
         }
+        else {
+            context.recordConflict(element, annotatedType, "Not expected here: " + name);
+        }
 
-        return null;
+        return name;
     }
 
     static final class FlushModeProcessor implements AnnotationProcessor {
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             // TODO: andrus, 4/23/2006 - where does this annotation belong??
 
@@ -109,7 +104,7 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
         }
     }
 
@@ -117,11 +112,11 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             JpaEmbeddedId id = new JpaEmbeddedId();
             id.setName(getMemberName(element, context, EmbeddedId.class));
-            
+
             Object parent = context.peek();
             if (parent instanceof JpaAbstractEntity) {
                 ((JpaAbstractEntity) parent).setEmbeddedId(id);
@@ -130,13 +125,13 @@
                 context.recordConflict(element, AnnotationProcessorFactory
                         .annotationClass(getClass()), "Unsupported in this place");
             }
-            
+
             context.push(id);
         }
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             context.pop();
         }
@@ -146,7 +141,7 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             JpaId id = new JpaId();
             id.setName(getMemberName(element, context, Id.class));
@@ -165,7 +160,7 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             context.pop();
         }
@@ -175,7 +170,7 @@
 
         public void onStartElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             Object parent = context.peek();
 
@@ -223,7 +218,7 @@
 
         public void onFinishElement(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
 
             Object stackTop = context.peek();
             if (stackTop instanceof JpaAttribute) {
@@ -237,31 +232,31 @@
         void onEmbeddedId(
                 JpaEmbeddedId id,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
-        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
         void onEmbeddableAttribute(
                 JpaEmbeddableAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             recordUnsupportedAnnotation(element, context);
         }
 
         void recordUnsupportedAnnotation(
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             context.recordConflict(element, AnnotationProcessorFactory
                     .annotationClass(getClass()), "Unsupported in this place");
         }
@@ -275,7 +270,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             AttributeOverride annotation = element.getAnnotation(AttributeOverride.class);
             attribute.getAttributeOverrides().add(new JpaAttributeOverride(annotation));
         }
@@ -284,7 +279,7 @@
         void onEmbeddedId(
                 JpaEmbeddedId id,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             AttributeOverride annotation = element.getAnnotation(AttributeOverride.class);
             id.getAttributeOverrides().add(new JpaAttributeOverride(annotation));
         }
@@ -296,7 +291,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             AttributeOverrides annotation = element
                     .getAnnotation(AttributeOverrides.class);
 
@@ -310,7 +305,7 @@
         void onEmbeddedId(
                 JpaEmbeddedId id,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             AttributeOverrides annotation = element
                     .getAnnotation(AttributeOverrides.class);
 
@@ -327,7 +322,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setBasic(new JpaBasic(element.getAnnotation(Basic.class)));
         }
 
@@ -335,7 +330,7 @@
         void onEmbeddableAttribute(
                 JpaEmbeddableAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setBasic(new JpaBasic(element.getAnnotation(Basic.class)));
         }
     }
@@ -346,7 +341,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             Column annotation = element.getAnnotation(Column.class);
             attribute.setColumn(new JpaColumn(annotation));
         }
@@ -355,13 +350,13 @@
         void onEmbeddableAttribute(
                 JpaEmbeddableAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             Column annotation = element.getAnnotation(Column.class);
             attribute.setColumn(new JpaColumn(annotation));
         }
 
         @Override
-        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorStack context) {
             Column annotation = element.getAnnotation(Column.class);
             id.setColumn(new JpaColumn(annotation));
         }
@@ -373,7 +368,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setEmbedded(true);
         }
     }
@@ -384,7 +379,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             Enumerated annotation = element.getAnnotation(Enumerated.class);
             attribute.setEnumerated(annotation.value());
         }
@@ -393,7 +388,7 @@
         void onEmbeddableAttribute(
                 JpaEmbeddableAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             Enumerated annotation = element.getAnnotation(Enumerated.class);
             attribute.setEnumerated(annotation.value());
         }
@@ -402,7 +397,7 @@
     static final class GeneratedValueProcessor extends AbstractChildProcessor {
 
         @Override
-        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorStack context) {
             GeneratedValue annotation = element.getAnnotation(GeneratedValue.class);
             id.setGeneratedValue(new JpaGeneratedValue(annotation));
         }
@@ -414,7 +409,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             JoinColumn annotation = element.getAnnotation(JoinColumn.class);
             attribute.getJoinColumns().add(new JpaJoinColumn(annotation));
         }
@@ -426,7 +421,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             JoinColumns annotation = element.getAnnotation(JoinColumns.class);
 
             for (int i = 0; i < annotation.value().length; i++) {
@@ -441,7 +436,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             JoinTable annotation = element.getAnnotation(JoinTable.class);
             attribute.setJoinTable(new JpaJoinTable(annotation));
         }
@@ -453,7 +448,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setLob(true);
         }
 
@@ -461,7 +456,7 @@
         void onEmbeddableAttribute(
                 JpaEmbeddableAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setLob(true);
         }
     }
@@ -472,7 +467,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             ManyToMany annotation = element.getAnnotation(ManyToMany.class);
             attribute.setManyToMany(new JpaManyToMany(annotation));
         }
@@ -484,7 +479,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setManyToOne(new JpaManyToOne(element
                     .getAnnotation(ManyToOne.class)));
         }
@@ -496,7 +491,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             MapKey annotation = element.getAnnotation(MapKey.class);
             attribute.setMapKey(annotation.name());
         }
@@ -508,7 +503,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setOneToMany(new JpaOneToMany(element
                     .getAnnotation(OneToMany.class)));
         }
@@ -520,7 +515,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setOneToOne(new JpaOneToOne(element.getAnnotation(OneToOne.class)));
         }
     }
@@ -531,7 +526,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             OrderBy annotation = element.getAnnotation(OrderBy.class);
             attribute.setOrderBy(annotation.value());
         }
@@ -543,7 +538,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             Temporal annotation = element.getAnnotation(Temporal.class);
             attribute.setTemporal(annotation.value());
         }
@@ -552,13 +547,13 @@
         void onEmbeddableAttribute(
                 JpaEmbeddableAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             Temporal annotation = element.getAnnotation(Temporal.class);
             attribute.setTemporal(annotation.value());
         }
 
         @Override
-        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorStack context) {
             Temporal annotation = element.getAnnotation(Temporal.class);
             id.setTemporal(annotation.value());
         }
@@ -570,7 +565,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setTransient(true);
         }
     }
@@ -581,7 +576,7 @@
         void onAttribute(
                 JpaAttribute attribute,
                 AnnotatedElement element,
-                AnnotationProcessorContext context) {
+                AnnotationProcessorStack context) {
             attribute.setVersion(true);
         }
     }