You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2008/01/10 21:44:39 UTC

svn commit: r610924 - in /openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-kernel/src/main/java/org/apache/openjpa/meta/ openjpa-kernel/src/main/java/org/apache/open...

Author: pcl
Date: Thu Jan 10 12:44:35 2008
New Revision: 610924

URL: http://svn.apache.org/viewvc?rev=610924&view=rev
Log:
OPENJPA-147 -- managed interface support. Also includes failure test case for OPENJPA-481.

Added:
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedIface.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceEmbed.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceOwner.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceSup.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterface.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterfaceImpl.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterface.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterfaceImpl.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/SimpleManagedInterface.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestManagedInterfaces.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestSimpleManagedInterface.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ManagedInterface.java
Modified:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
    openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EmbedValue.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestEJBEmbedded.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
    openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java Thu Jan 10 12:44:35 2008
@@ -176,7 +176,9 @@
     private boolean _bcsConfigured = false;
 
     /**
-     * Constructor. Supply configuration and type to enhance.
+     * Constructor. Supply configuration and type to enhance. This will look
+     * up the metadata for <code>type</code> from <code>conf</code>'s
+     * repository.
      */
     public PCEnhancer(OpenJPAConfiguration conf, Class type) {
         this(conf, (BCClass) AccessController.doPrivileged(J2DoPrivHelper
@@ -185,12 +187,14 @@
     }
 
     /**
-     * Constructor. Supply configuration and type to enhance.
+     * Constructor. Supply configuration and type to enhance. This will look
+     * up the metadata for <code>meta</code> by converting back to a class
+     * and then loading from <code>conf</code>'s repository.
      */
-    public PCEnhancer(OpenJPAConfiguration conf, ClassMetaData type) {
+    public PCEnhancer(OpenJPAConfiguration conf, ClassMetaData meta) {
         this(conf, (BCClass) AccessController.doPrivileged(J2DoPrivHelper
-            .loadProjectClassAction(new Project(), type.getDescribedType())),
-            type.getRepository());
+            .loadProjectClassAction(new Project(), meta.getDescribedType())),
+            meta.getRepository());
     }
 
     /**
@@ -241,6 +245,36 @@
         _meta = _repos.getMetaData(type.getType(), loader, false);
     }
 
+    /**
+     * Constructor. Supply repository. The repository's configuration will
+     * be used, and the metadata passed in will be used as-is without doing
+     * any additional lookups. This is useful when running the enhancer
+     * during metadata load.
+     *
+     * @param repos a metadata repository to use for metadata access,
+     * or null to create a new reporitory; the repository
+     * from the given configuration isn't used by default
+     * because the configuration might be an
+     * implementation-specific subclass whose metadata
+     * required more than just base metadata files
+     * @param type the bytecode representation fo the type to
+     * enhance; this can be created from any stream or file
+     * @param meta the metadata to use for processing this type.
+     *
+     * @since 1.1.0
+     */
+    public PCEnhancer(MetaDataRepository repos, BCClass type,
+        ClassMetaData meta) {
+        _managedType = type;
+        _pc = type;
+
+        _log = repos.getConfiguration()
+            .getLog(OpenJPAConfiguration.LOG_ENHANCE);
+
+        _repos = repos;
+        _meta = meta;
+    }
+
     static String toPCSubclassName(Class cls) {
         return Strings.getPackageName(PCEnhancer.class) + "."
             + cls.getName().replace('.', '$') + "$pcsubclass";
@@ -453,7 +487,7 @@
 
         try {
             // if managed interface, skip
-            if (_managedType.isInterface())
+            if (_pc.isInterface())
                 return ENHANCE_INTERFACE;
 
             // check if already enhanced
@@ -526,8 +560,6 @@
                 } else {
                     _isAlreadySubclassed = true;
                 }
-            } else {
-                _pc = _managedType;
             }
 
             _bcsConfigured = true;
@@ -2656,8 +2688,10 @@
             }
 
             // pcPCSuperclass = <superClass>;
-            code.classconstant().setClass(getType(_meta.
-                getPCSuperclassMetaData()));
+            // this intentionally calls getDescribedType() directly
+            // instead of PCEnhancer.getType()
+            code.classconstant().setClass(
+                _meta.getPCSuperclassMetaData().getDescribedType());
             code.putstatic().setField(SUPER, Class.class);
         }
 
@@ -2698,7 +2732,7 @@
         // PCRegistry.register (cls,
         //	pcFieldNames, pcFieldTypes, pcFieldFlags,
         //  pcPCSuperclass, alias, new XXX ());
-        code.classconstant().setClass(_managedType);
+        code.classconstant().setClass(_meta.getDescribedType());
         code.getstatic().setField(PRE + "FieldNames", String[].class);
         code.getstatic().setField(PRE + "FieldTypes", Class[].class);
         code.getstatic().setField(PRE + "FieldFlags", byte[].class);
@@ -3627,19 +3661,19 @@
         // first, see if we can convert the attribute name to a field name
         String fieldName = toBackingFieldName(attrName);
 
-        // next, find the field in the managed type.
-        BCField[] fields = (BCField[]) AccessController
-            .doPrivileged(J2DoPrivHelper.getBCClassFieldsAction(_managedType,
-                fieldName)); 
+        // next, find the field in the managed type hierarchy
         BCField field = null;
-        for (int i = 0; i < fields.length; i++) {
-            field = fields[i];
-            // if we reach a field declared in this type, then this is the
-            // most-masking field, and is the one that we want.
-            // ##### probably should walk up the hierarchy, or check that
-            // ##### serp does that.
-            if (fields[i].getDeclarer() == declarer) {
-                break;
+        outer: for (BCClass bc = _pc; bc != null; bc = bc.getSuperclassBC()) {
+            BCField[] fields = (BCField[]) AccessController
+                .doPrivileged(J2DoPrivHelper.getBCClassFieldsAction(bc,
+                    fieldName));
+            for (int i = 0; i < fields.length; i++) {
+                field = fields[i];
+                // if we reach a field declared in this type, then this is the
+                // most-masking field, and is the one that we want.
+                if (fields[i].getDeclarer() == declarer) {
+                    break outer;
+                }
             }
         }
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java Thu Jan 10 12:44:35 2008
@@ -28,6 +28,7 @@
 import org.apache.openjpa.lib.util.ReferenceMap;
 import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
 import org.apache.openjpa.util.UserException;
+import org.apache.openjpa.util.InvalidStateException;
 
 /**
  * Tracks registered persistence-capable classes.

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Broker.java Thu Jan 10 12:44:35 2008
@@ -557,7 +557,11 @@
      * an interface or an abstract class whose abstract methods follow the
      * JavaBeans convention, this method will create a concrete implementation
      * according to the metadata that defines the class.
-     * Otherwise, this will return an instance of the specified class.
+     * Otherwise, if <code>cls</code> is a managed type, this will return an
+     * instance of the specified class.
+     *
+     * @throws IllegalArgumentException if <code>cls</code> is not a managed
+     * type or interface.
      */
     public Object newInstance(Class cls);
 

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Thu Jan 10 12:44:35 2008
@@ -2641,8 +2641,6 @@
             PersistenceCapable copy;
             PCState state;
             Class type = meta.getDescribedType();
-            if (type.isInterface())
-                type = meta.getInterfaceImpl();
             if (obj != null) {
                 // give copy and the original instance the same state manager
                 // so that we can copy fields from one to the other
@@ -4152,11 +4150,7 @@
     public Object newInstance(Class cls) {
         assertOpen();
 
-        if (cls.isInterface()) {
-            ClassMetaData meta = _conf.getMetaDataRepositoryInstance().
-                getMetaData(cls, _loader, true);
-            cls = meta.getInterfaceImpl();
-        } else if (Modifier.isAbstract(cls.getModifiers()))
+        if (!cls.isInterface() && Modifier.isAbstract(cls.getModifiers()))
             throw new UnsupportedOperationException(_loc.get
                 ("new-abstract", cls).getMessage());
 
@@ -4169,7 +4163,14 @@
             } catch (Throwable t) {
             }
         }
-        return PCRegistry.newInstance(cls, null, false);
+        try {
+            return PCRegistry.newInstance(cls, null, false);
+        } catch (IllegalStateException ise) {
+            IllegalArgumentException iae =
+                new IllegalArgumentException(ise.getMessage());
+            iae.setStackTrace(ise.getStackTrace());
+            throw iae;
+        }
     }
 
     public Object getObjectId(Object obj) {

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java Thu Jan 10 12:44:35 2008
@@ -260,8 +260,6 @@
             }
             _meta = sub;
         }
-        if (cls.isInterface())
-            cls = _meta.getInterfaceImpl();
 
         PersistenceCapable inst = PCRegistry.newInstance(cls, this, _oid, true);
         if (inst == null) {
@@ -814,7 +812,8 @@
 
         SaveFieldManager saved = getSaveFieldManager();
         if (saved == null)
-            throw new InternalException(_loc.get("no-saved-fields"));
+            throw new InternalException(_loc.get("no-saved-fields",
+                getMetaData().getDescribedType().getName()));
 
         FieldMetaData[] fmds = getMetaData().getFields();
         for (int i = 0; i < fmds.length; i++) {

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java Thu Jan 10 12:44:35 2008
@@ -180,6 +180,8 @@
      */
     private boolean populateFromPCRegistry(ClassMetaData meta) {
         Class cls = meta.getDescribedType();
+        if (!PCRegistry.isRegistered(cls))
+            return false;
         try {
             String[] fieldNames = PCRegistry.getFieldNames(cls);
             Class[] fieldTypes = PCRegistry.getFieldTypes(cls);
@@ -198,9 +200,6 @@
                 populate(fmd);
             }
             return true;
-        } catch (IllegalStateException iae) {
-            // thrown by registry when no metadata available
-            return false;
         } catch (OpenJPAException ke) {
             throw ke;
         } catch (Exception e) {

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java Thu Jan 10 12:44:35 2008
@@ -732,6 +732,11 @@
         if (!_type.isInterface())
             throw new MetaDataException(_loc.get("not-interface", _type));
         _interface = managedInterface ? Boolean.TRUE : Boolean.FALSE;
+
+        // managed interfaces always do proper interception; OpenJPA generates
+        // the implementations.
+        if (isManagedInterface())
+            setIntercepting(true);
     }
 
     /**
@@ -2235,6 +2240,7 @@
         _extent = (meta.getRequiresExtent()) ? Boolean.TRUE : Boolean.FALSE;
         _embedded = (meta.isEmbeddedOnly()) ? Boolean.TRUE : Boolean.FALSE;
         _interface = (meta.isManagedInterface()) ? Boolean.TRUE : Boolean.FALSE;
+        setIntercepting(meta.isIntercepting());
         _impl = meta.getInterfaceImpl();
         _identity = meta.getIdentityType();
         _idStrategy = meta.getIdentityStrategy();

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java Thu Jan 10 12:44:35 2008
@@ -114,14 +114,13 @@
         // copy the BCClass into the enhancer project.
         bc = _enhProject.loadClass(new ByteArrayInputStream(bc.toByteArray()), 
             loader);
-        PCEnhancer enhancer = new PCEnhancer(_repos.getConfiguration(), bc, 
-            meta);
+        PCEnhancer enhancer = new PCEnhancer(_repos, bc, meta);
 
         int result = enhancer.run();
         if (result != PCEnhancer.ENHANCE_PC)
             throw new InternalException(_loc.get("interface-badenhance", 
                 iface)).setFatal(true);
-        try{
+        try {
             // load the class for real.
             impl = Class.forName(bc.getName(), true, enhLoader);
         } catch (Throwable t) {
@@ -228,5 +227,19 @@
             return meth == null;
         } catch (PrivilegedActionException pae) {}
         return true;
+    }
+
+    boolean isImplType(Class cls) {
+        return (cls.getName().endsWith(POSTFIX)
+            && cls.getName().indexOf('$') != -1);
+    }
+
+    public Class toManagedInterface(Class cls) {
+        Class[] ifaces = cls.getInterfaces();
+        for (int i = 0; i < ifaces.length; i++) {
+            if (_impls.get(ifaces[i]) == cls)
+                return ifaces[i];
+        }
+        throw new IllegalArgumentException(cls.getName());
     }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java Thu Jan 10 12:44:35 2008
@@ -287,6 +287,11 @@
             DynamicPersistenceCapable.class.isAssignableFrom(cls))
             cls = cls.getSuperclass();
 
+        // if cls is a generated interface, use the user interface
+        // to locate metadata
+        if (cls != null && _implGen.isImplType(cls))
+            cls = _implGen.toManagedInterface(cls);
+
         ClassMetaData meta = getMetaDataInternal(cls, envLoader);
         if (meta == null && mustExist) {
             if (cls != null &&
@@ -952,7 +957,6 @@
             throw new MetaDataException(_loc.get("not-managed-interface", 
                 meta, impl));
         _ifaces.put(meta.getDescribedType(), impl);
-        _metas.put(impl, meta);
         addDeclaredInterfaceImpl(meta, meta.getDescribedType());
         ClassMetaData sup = meta.getPCSuperclassMetaData();
         while (sup != null) {
@@ -964,9 +968,7 @@
         }
     }
     
-    synchronized InterfaceImplGenerator getImplGenerator() {
-        if (_implGen == null)
-            _implGen = new InterfaceImplGenerator(this);
+    InterfaceImplGenerator getImplGenerator() {
         return _implGen;
     }
 
@@ -1278,6 +1280,11 @@
             cls = classForName((String) itr.next(), clsLoader);
             if (cls != null)
                 classes.add(cls);
+
+            // if the class is an interface, load its metadata to kick
+            // off the impl generator
+            if (cls.isInterface())
+                getMetaData(cls, clsLoader, false);
         }
         return classes;
     }
@@ -1548,6 +1555,8 @@
 
     public void endConfiguration() {
         initializeMetaDataFactory();
+        if (_implGen == null)
+            _implGen = new InterfaceImplGenerator(this);
     }
 
     private void initializeMetaDataFactory() {

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java Thu Jan 10 12:44:35 2008
@@ -301,9 +301,7 @@
         // oid instance
         if (!Modifier.isAbstract(meta.getDescribedType().getModifiers())
             && !hasPCPrimaryKeyFields(meta)) {
-            Class type = meta.getInterfaceImpl();
-            if (type == null)
-                type = meta.getDescribedType();
+            Class type = meta.getDescribedType();
             PersistenceCapable pc = PCRegistry.newInstance(type, null, oid, 
                  false);
             Object copy = pc.pcNewObjectIdInstance();

Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties Thu Jan 10 12:44:35 2008
@@ -388,11 +388,11 @@
     single broker. By default brokers are not thread safe; if you require \
     and/or intend a broker to be accessed by more than one thread, set the \
     openjpa.Multithreaded property to true to override the default behavior.
-no-saved-fields: No state snapshot is available for "{0}", but this instance \
-    uses state-comparison for dirty detection.
+no-saved-fields: No state snapshot is available for instance of type "{0}", \
+    but this instance uses state-comparison for dirty detection.
 cant-serialize-flushed-broker: Serialization not allowed once a broker has \
     been flushed.
 cant-serialize-pessimistic-broker: Serialization not allowed for brokers with \
     an active datastore (pessimistic) transaction.
 cant-serialize-connected-broker: Serialization not allowed for brokers with \
-    an active connection to the database.
\ No newline at end of file
+    an active connection to the database.

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EmbedValue.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EmbedValue.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EmbedValue.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EmbedValue.java Thu Jan 10 12:44:35 2008
@@ -40,6 +40,9 @@
     @JoinColumn(name = "EMB_REL")
     protected EmbedOwner owner;
 
+    @Transient
+    private int transientField;
+
     public void setBasic(String basic) {
         this.basic = basic;
     }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestEJBEmbedded.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestEJBEmbedded.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestEJBEmbedded.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestEJBEmbedded.java Thu Jan 10 12:44:35 2008
@@ -29,6 +29,9 @@
 import org.apache.openjpa.jdbc.meta.strats.StringFieldStrategy;
 import org.apache.openjpa.jdbc.sql.DBDictionary;
 import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+import org.apache.openjpa.persistence.JPAFacadeHelper;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
 
 /**
  * Test for embedded
@@ -76,6 +79,15 @@
         assertEquals("foobar", new String(embed.getBlob()));
         assertEquals(owner, embed.getOwner());
         em.close();
+    }
+
+    public void testEmbeddedMetaData() {
+        ClassMetaData ownerMeta =
+            JPAFacadeHelper.getMetaData(emf, EmbedOwner.class);
+        FieldMetaData fmd = ownerMeta.getField("embed");
+        ClassMetaData embeddedMeta = fmd.getDefiningMetaData();
+        assertNotNull(embeddedMeta);
+        assertNull(embeddedMeta.getField("transientField"));
     }
 
     public void testNull() {

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedIface.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedIface.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedIface.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedIface.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,47 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+
+import java.util.*;
+
+import javax.persistence.Entity;
+import javax.persistence.Embedded;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.CascadeType;
+
+import org.apache.openjpa.persistence.PersistentCollection;
+import org.apache.openjpa.persistence.ManagedInterface;
+import org.apache.openjpa.persistence.query.SimpleEntity;
+
+@ManagedInterface
+@Entity
+public interface ManagedIface extends ManagedInterfaceSup {
+    public int getIntField();
+    public void setIntField(int i);
+
+    @Embedded
+    public ManagedInterfaceEmbed getEmbed();
+    public void setEmbed(ManagedInterfaceEmbed embed);
+
+    @OneToOne(cascade=CascadeType.PERSIST)
+    public ManagedIface getSelf();
+    public void setSelf(ManagedIface iface);
+
+    @PersistentCollection
+    public Set<Integer> getSetInteger();
+    public void setSetInteger(Set<Integer> collection);
+
+    @OneToMany(cascade=CascadeType.PERSIST)
+    public Set<SimpleEntity> getSetPC();
+    public void setSetPC(Set<SimpleEntity> collection);
+
+    @OneToMany(cascade=CascadeType.PERSIST)
+    public Set<ManagedIface> getSetI();
+    public void setSetI(Set<ManagedIface> collection);
+
+    @OneToOne(cascade=CascadeType.PERSIST)
+    public SimpleEntity getPC();
+    public void setPC(SimpleEntity pc);
+
+    public void unimplemented();
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceEmbed.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceEmbed.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceEmbed.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceEmbed.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,13 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Basic;
+
+import org.apache.openjpa.persistence.ManagedInterface;
+
+@ManagedInterface
+@Embeddable
+public interface ManagedInterfaceEmbed {
+    public int getEmbedIntField();
+    public void setEmbedIntField(int i);
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceOwner.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceOwner.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceOwner.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceOwner.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,46 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+import javax.persistence.OneToOne;
+import javax.persistence.Id;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.CascadeType;
+
+@Entity
+public class ManagedInterfaceOwner {
+
+    @Id
+    private int id;
+
+    private int intField;
+
+    @OneToOne(cascade=CascadeType.PERSIST)
+    private ManagedInterfaceSup iface;
+
+    @Embedded
+    private ManagedInterfaceEmbed embed;
+
+    public int getIntField() {
+        return intField;
+    }
+
+    public void setIntField(int i) {
+        intField = i;
+    }
+
+    public ManagedInterfaceSup getIFace() {
+        return iface;
+    }
+
+    public void setIFace(ManagedInterfaceSup iface) {
+        this.iface = iface;
+    }
+
+    public ManagedInterfaceEmbed getEmbed() {
+        return embed;
+    }
+
+    public void setEmbed(ManagedInterfaceEmbed embed) {
+        this.embed = embed;
+    }
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceSup.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceSup.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceSup.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/ManagedInterfaceSup.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,18 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+import org.apache.openjpa.persistence.ManagedInterface;
+
+@ManagedInterface
+@Entity
+public interface ManagedInterfaceSup {
+    @Id @GeneratedValue
+    public int getId();
+    public void setId(int id);
+
+    public int getIntFieldSup();
+    public void setIntFieldSup(int i);
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterface.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterface.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterface.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterface.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,20 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.apache.openjpa.persistence.ManagedInterface;
+
+@ManagedInterface
+@Entity
+public interface MixedInterface {
+
+    @Id
+    @GeneratedValue
+    public int getId();
+    public void setId(int id);
+
+    public int getIntField();
+    public void setIntField(int i);
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterfaceImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterfaceImpl.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterfaceImpl.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/MixedInterfaceImpl.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,30 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+@Entity
+public class MixedInterfaceImpl implements MixedInterface {
+    @Id
+    @GeneratedValue
+    private int id;
+
+    private int intField;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public int getIntField() {
+        return intField;
+    }
+
+    public void setIntField(int i) {
+        intField = i;
+    }
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterface.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterface.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterface.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterface.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,8 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+
+public interface NonMappedInterface {
+    public int getIntField();
+
+    public void setIntField(int i);
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterfaceImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterfaceImpl.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterfaceImpl.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/NonMappedInterfaceImpl.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,17 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+import javax.persistence.Entity;
+
+@Entity
+public class NonMappedInterfaceImpl
+    implements NonMappedInterface {
+    private int mismatch;
+
+    public int getIntField() {
+        return mismatch;
+    }
+
+    public void setIntField(int i) {
+        mismatch = i;
+    }
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/SimpleManagedInterface.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/SimpleManagedInterface.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/SimpleManagedInterface.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/SimpleManagedInterface.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,36 @@
+/*
+ * 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.openjpa.persistence.managedinterface;
+
+import javax.persistence.Id;
+import javax.persistence.Entity;
+
+import org.apache.openjpa.persistence.ManagedInterface;
+
+@ManagedInterface
+@Entity
+public interface SimpleManagedInterface {
+
+    @Id
+    public int getId();
+    public void setId(int id);
+
+    public String getString();
+    public void setString(String s);
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestManagedInterfaces.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestManagedInterfaces.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestManagedInterfaces.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestManagedInterfaces.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,449 @@
+package org.apache.openjpa.persistence.managedinterface;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import javax.persistence.Query;
+import javax.persistence.EntityNotFoundException;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+import org.apache.openjpa.persistence.OpenJPAEntityManager;
+import org.apache.openjpa.persistence.JPAFacadeHelper;
+import org.apache.openjpa.persistence.Extent;
+import org.apache.openjpa.persistence.query.SimpleEntity;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.persistence.PersistenceException;
+
+public class TestManagedInterfaces extends SingleEMFTestCase {
+
+    @Override
+    public void setUp() {
+        super.setUp(SimpleEntity.class, ManagedInterfaceEmbed.class,
+            ManagedInterfaceSup.class, ManagedIface.class,
+            ManagedInterfaceOwner.class, MixedInterface.class,
+            MixedInterfaceImpl.class, NonMappedInterfaceImpl.class,
+            CLEAR_TABLES);
+    }
+
+    public void testEmbeddedMetaData() {
+        emf.createEntityManager().close();
+        ClassMetaData ownerMeta = JPAFacadeHelper.getMetaData(emf,
+            ManagedIface.class);
+        ClassMetaData embeddedMeta = ownerMeta.getField("embed")
+            .getDefiningMetaData();
+        assertTrue(embeddedMeta.isManagedInterface());
+        assertTrue(embeddedMeta.isIntercepting());
+
+        ClassMetaData embeddableMeta = JPAFacadeHelper.getMetaData(emf,
+            ManagedInterfaceEmbed.class);
+        assertTrue(embeddableMeta.isManagedInterface());
+        assertTrue(embeddableMeta.isIntercepting());
+    }
+
+    public void testManagedInterface() throws Exception {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        ManagedIface pc = em.createInstance(ManagedIface.class);
+        pc.setIntFieldSup(3);
+        pc.setIntField(4);
+        pc.setEmbed(em.createInstance(ManagedInterfaceEmbed.class));
+
+        pc.getEmbed().setEmbedIntField(5);
+        assertEquals(5, pc.getEmbed().getEmbedIntField());
+        em.persist(pc);
+        Object oid = em.getObjectId(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        assertEquals(3, pc.getIntFieldSup());
+        assertEquals(4, pc.getIntField());
+        assertEquals(5, pc.getEmbed().getEmbedIntField());
+        em.getTransaction().begin();
+        pc.setIntField(14);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager ();
+        em.getTransaction().begin();
+        Query query = em.createQuery("select o from ManagedIface o " +
+            "where o.intField = 14");
+        pc = (ManagedIface) query.getSingleResult();
+        assertEquals(14, pc.getIntField());
+        em.remove(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        try {
+            assertNull(em.find(ManagedIface.class, oid));
+        } catch (EntityNotFoundException onfe) {}
+
+        em.close();
+    }
+
+    public void testInterfaceOwner() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        ManagedInterfaceOwner pc = new ManagedInterfaceOwner();
+        pc.setIFace(em.createInstance(ManagedInterfaceSup.class));
+        pc.setEmbed(em.createInstance(ManagedInterfaceEmbed.class));
+        pc.getIFace().setIntFieldSup(3);
+        pc.getEmbed().setEmbedIntField(5);
+
+        em.getTransaction().begin();
+        em.persist(pc);
+        Object oid = em.getObjectId(pc);
+        em.getTransaction().commit();
+        pc = em.find(ManagedInterfaceOwner.class, oid);
+        assertEquals(3, pc.getIFace().getIntFieldSup());
+        assertEquals(5, pc.getEmbed().getEmbedIntField());
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedInterfaceOwner.class, oid);
+        assertEquals(3, pc.getIFace().getIntFieldSup());
+        assertEquals(5, pc.getEmbed().getEmbedIntField());
+        em.close();
+
+        em = emf.createEntityManager();
+        em.getTransaction().begin();
+        Query q = em.createQuery("select o from ManagedInterfaceOwner o " +
+            "where o.iface.intFieldSup = 3 and o.embed.embedIntField = 5");
+        pc = (ManagedInterfaceOwner) q.getSingleResult();
+        assertEquals(3, pc.getIFace().getIntFieldSup());
+        assertEquals(5, pc.getEmbed().getEmbedIntField());
+
+        pc.getIFace().setIntFieldSup(13);
+        pc.getEmbed().setEmbedIntField(15);
+        assertEquals(13, pc.getIFace().getIntFieldSup());
+        assertEquals(15, pc.getEmbed().getEmbedIntField());
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedInterfaceOwner.class, oid);
+        assertEquals(13, pc.getIFace().getIntFieldSup());
+        assertEquals(15, pc.getEmbed().getEmbedIntField());
+        em.close();
+    }
+
+    public void testCollection() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        ManagedIface pc = em.createInstance(ManagedIface.class);
+        Set set = new HashSet();
+        set.add(new Integer(3));
+        set.add(new Integer(4));
+        set.add(new Integer(5));
+        pc.setSetInteger(set);
+        em.persist(pc);
+        Object oid = em.getObjectId(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetInteger();
+        assertEquals(3, set.size());
+        assertTrue(set.contains(new Integer(3)));
+        assertTrue(set.contains(new Integer(4)));
+        assertTrue(set.contains(new Integer(5)));
+        em.getTransaction().begin();
+        set.remove(new Integer(4));
+        set.add(new Integer(14));
+        set.add(new Integer(15));
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetInteger();
+        assertEquals(4, set.size());
+        assertTrue(set.contains(new Integer(3)));
+        assertTrue(set.contains(new Integer(5)));
+        assertTrue(set.contains(new Integer(14)));
+        assertTrue(set.contains(new Integer(15)));
+        em.getTransaction().begin();
+        pc.setSetInteger(null);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetInteger();
+        assertTrue (set == null || set.size() == 0);
+        em.close();
+    }
+
+    public void testCollectionPC() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        ManagedIface pc = em.createInstance(ManagedIface.class);
+        Set set = new HashSet();
+        set.add(new SimpleEntity("a", "3"));
+        set.add(new SimpleEntity("b", "4"));
+        set.add(new SimpleEntity("c", "5"));
+        pc.setSetPC(set);
+        em.persist(pc);
+        Object oid = em.getObjectId(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetPC();
+        assertEquals(3, set.size());
+        Collection seen = new ArrayList();
+        SimpleEntity rel;
+        SimpleEntity toRem = null;
+        for (Iterator it = set.iterator(); it.hasNext();) {
+            rel = (SimpleEntity) it.next();
+            seen.add(rel.getName());
+            if (rel.getValue().equals("4"))
+                toRem = rel;
+        }
+        assertEquals(3, seen.size());
+        assertTrue(seen.contains("a"));
+        assertTrue(seen.contains("b"));
+        assertTrue(seen.contains("c"));
+        em.getTransaction().begin();
+        assertNotNull(toRem);
+        set.remove(toRem);
+        set.add(new SimpleEntity("x", "14"));
+        set.add(new SimpleEntity("y", "15"));
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetPC();
+        assertEquals(4, set.size());
+        seen.clear();
+        for (Iterator it = set.iterator(); it.hasNext();) {
+            rel = (SimpleEntity) it.next();
+            seen.add(rel.getName());
+        }
+        assertEquals(4, seen.size());
+        assertTrue(seen.contains("a"));
+        assertTrue(seen.contains("c"));
+        assertTrue(seen.contains("x"));
+        assertTrue(seen.contains("y"));
+        em.getTransaction().begin();
+        pc.setSetPC(null);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetPC();
+        assertTrue (set == null || set.size() == 0);
+        em.close();
+    }
+
+    public void testCollectionInterfaces() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        ManagedIface pc = em.createInstance(ManagedIface.class);
+        Set set = new HashSet();
+        set.add(createInstance(em, 3));
+        set.add(createInstance(em, 4));
+        set.add(createInstance(em, 5));
+        pc.setSetI(set);
+        em.persist(pc);
+        Object oid = em.getObjectId(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetI();
+        assertEquals(3, set.size());
+        Collection seen = new ArrayList();
+        ManagedIface rel = null;
+        ManagedIface toRem = null;
+        for (Iterator it = set.iterator(); it.hasNext();) {
+            rel = (ManagedIface) it.next();
+            seen.add(new Integer(rel.getIntField()));
+            if (rel.getIntField() == 4)
+                toRem = rel;
+        }
+        assertEquals(3, seen.size());
+        assertTrue(seen.contains(new Integer(3)));
+        assertTrue(seen.contains(new Integer(4)));
+        assertTrue(seen.contains(new Integer(5)));
+        em.getTransaction().begin();
+        assertNotNull(toRem);
+        set.remove(toRem);
+        set.add(createInstance(em, 14));
+        set.add(createInstance(em, 15));
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetI();
+        assertEquals(4, set.size());
+        seen.clear();
+        for (Iterator it = set.iterator(); it.hasNext();) {
+            rel = (ManagedIface) it.next();
+            seen.add(new Integer(rel.getIntField()));
+        }
+        assertEquals(4, seen.size());
+        assertTrue(seen.contains(new Integer(3)));
+        assertTrue(seen.contains(new Integer(5)));
+        assertTrue(seen.contains(new Integer(14)));
+        assertTrue(seen.contains(new Integer(15)));
+        em.getTransaction().begin();
+        pc.setSetPC(null);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        set = pc.getSetPC();
+        assertTrue (set == null || set.size() == 0);
+        em.close();
+    }
+
+    public void testMixedQuery() {
+        createMixed();
+
+        OpenJPAEntityManager em = emf.createEntityManager();
+        try {
+            Query q = em.createQuery("select o from MixedInterface o " +
+                "where o.intField = 4");
+            Collection c = q.getResultList();
+            Set seen = new HashSet();
+            assertEquals(2, c.size());
+            MixedInterface pc;
+            for (Iterator it = c.iterator(); it.hasNext();) {
+                pc = (MixedInterface) it.next();
+                assertEquals(4, pc.getIntField());
+                seen.add(pc.getClass());
+            }
+            assertEquals(2, seen.size());
+
+            fail("OPENJPA-481");
+        } catch (PersistenceException e) {
+            // expected
+        } finally {
+            em.close();
+        }
+    }
+
+    public void testQueryForMixedInterfaceImpls() {
+        createMixed();
+
+        OpenJPAEntityManager em = emf.createEntityManager();
+        Query q = em.createQuery("select o from MixedInterfaceImpl o " +
+            "where o.intField = 4");
+        MixedInterface pc = (MixedInterface) q.getSingleResult();
+        assertEquals(4, pc.getIntField());
+        assertTrue(pc instanceof MixedInterfaceImpl);
+        em.close();
+    }
+
+    public void testMixedExtent() {
+        createMixed();
+
+        OpenJPAEntityManager em = emf.createEntityManager();
+        Extent e = em.createExtent(MixedInterface.class, true);
+        Set seen = new HashSet();
+        int size = 0;
+        for (Iterator it = e.iterator(); it.hasNext();) {
+            seen.add(it.next().getClass());
+            size++;
+        }
+        assertEquals(3, size);
+        assertEquals(2, seen.size());
+
+        e = em.createExtent(MixedInterface.class, false);
+        seen = new HashSet();
+        size = 0;
+        for (Iterator it = e.iterator(); it.hasNext();) {
+            seen.add(it.next().getClass());
+            size++;
+        }
+        assertEquals(1, size);
+        assertNotEquals(MixedInterfaceImpl.class, seen.iterator().next());
+        em.close();
+    }
+
+    private void createMixed() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        MixedInterface pc = em.createInstance(MixedInterface.class);
+        pc.setIntField(4);
+        em.persist(pc);
+        pc = new MixedInterfaceImpl();
+        pc.setIntField(4);
+        em.persist(pc);
+        pc = new MixedInterfaceImpl();
+        pc.setIntField(8);
+        em.persist(pc);
+        em.getTransaction().commit();
+        em.close();
+    }
+
+    public void testUnimplementedThrowsException() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        ManagedIface pc = createInstance(em, 1);
+        try {
+            pc.unimplemented();
+            fail("Exception expected.");
+        } catch (UnsupportedOperationException uoe) {} // good
+        em.close();
+    }
+
+    public void testNonMappedCreateInstanceException() {
+        // OpenJPA's support of non-mapped interfaces differs from JDO support;
+        // there is no special query or relation support for non-mapped
+        // interfaces in OpenJPA at this time.
+        OpenJPAEntityManager em = null;
+        try {
+            em = emf.createEntityManager();
+            em.createInstance(NonMappedInterface.class);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {} // good
+        if (em != null)
+            em.close();
+    }
+
+    public void testDetach() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        ManagedIface pc = createInstance(em, 4);
+        em.persist(pc);
+        Object oid = em.getObjectId(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        ManagedIface pcx = em.find(ManagedIface.class, oid);
+        pc = em.detach(pcx);
+        em.close();
+
+        assertTrue(em.isDetached(pc));
+        pc.setIntField(7);
+
+        em = emf.createEntityManager();
+        em.getTransaction().begin();
+        em.merge(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(ManagedIface.class, oid);
+        assertEquals(7, pc.getIntField());
+        em.close();
+    }
+
+    private ManagedIface createInstance(OpenJPAEntityManager em, int i) {
+        ManagedIface pc = em.createInstance(ManagedIface.class);
+        pc.setIntField(i);
+        return pc;
+    }
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestSimpleManagedInterface.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestSimpleManagedInterface.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestSimpleManagedInterface.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/managedinterface/TestSimpleManagedInterface.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,92 @@
+/*
+ * 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.openjpa.persistence.managedinterface;
+
+import javax.persistence.EntityManager;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+import org.apache.openjpa.persistence.JPAFacadeHelper;
+import org.apache.openjpa.persistence.OpenJPAEntityManager;
+import org.apache.openjpa.persistence.query.SimpleEntity;
+import org.apache.openjpa.kernel.AbstractBrokerFactory;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.MetaDataRepository;
+
+public class TestSimpleManagedInterface
+    extends SingleEMFTestCase {
+
+    public void setUp() {
+        setUp(SimpleManagedInterface.class, SimpleEntity.class, CLEAR_TABLES);
+    }
+
+    public void testMetaDataRepository() {
+        AbstractBrokerFactory bf =
+            (AbstractBrokerFactory) JPAFacadeHelper.toBrokerFactory(emf);
+        bf.makeReadOnly();
+        MetaDataRepository repos = bf.getConfiguration()
+            .getMetaDataRepositoryInstance();
+        ClassMetaData meta = repos.getMetaData(SimpleManagedInterface.class,
+            null, false);
+        assertNotNull(meta);
+        assertTrue(meta.isManagedInterface());
+        assertEquals(SimpleManagedInterface.class, meta.getDescribedType());
+    }
+
+    public void testInterfaceImplGeneration() {
+        ((AbstractBrokerFactory) JPAFacadeHelper.toBrokerFactory(emf))
+            .makeReadOnly();
+        // load metadata to trigger instance creation
+        ClassMetaData meta = JPAFacadeHelper.getMetaData(emf,
+            SimpleManagedInterface.class);
+        assertEquals(SimpleManagedInterface.class, meta.getDescribedType());
+    }
+
+    public void testBasicOperations() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        SimpleManagedInterface pc =
+            em.createInstance(SimpleManagedInterface.class);
+        pc.setId(17);
+        pc.setString("hello!");
+        em.getTransaction().begin();
+        em.persist(pc);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        pc = em.find(SimpleManagedInterface.class, 17);
+        assertNotNull(pc);
+        em.getTransaction().begin();
+        pc.setString("updated");
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        em.getTransaction().begin();
+        em.remove(em.getReference(SimpleManagedInterface.class, 17));
+        em.getTransaction().commit();
+        em.close();
+    }
+
+    public void testJPQL() {
+        EntityManager em = emf.createEntityManager();
+        assertEquals(0, em.createQuery("select o from SimpleManagedInterface o")
+            .getResultList().size());
+        em.close();
+    }
+}
\ No newline at end of file

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java Thu Jan 10 12:44:35 2008
@@ -172,6 +172,7 @@
         _tags.put(KeyType.class, KEY_TYPE);
         _tags.put(LoadFetchGroup.class, LOAD_FETCH_GROUP);
         _tags.put(LRS.class, LRS);
+        _tags.put(ManagedInterface.class, MANAGED_INTERFACE);
         _tags.put(ReadOnly.class, READ_ONLY);
         _tags.put(Type.class, TYPE);
     }
@@ -572,6 +573,10 @@
                     if (isMetaDataMode())
                         fgs = ((FetchGroups) anno).value();
                     break;
+                case MANAGED_INTERFACE:
+                    if (isMetaDataMode())
+                        parseManagedInterface(meta, (ManagedInterface) anno);
+                    break;
                 default:
                     throw new UnsupportedException(_loc.get("unsupported", _cls,
                         anno.toString()));
@@ -595,7 +600,8 @@
             // scan possibly non-PC hierarchy for callbacks.
             // redundant for PC superclass but we don't know that yet
             // so let LifecycleMetaData determine that
-            if (!Object.class.equals(_cls.getSuperclass())) {
+            if (_cls.getSuperclass() != null &&
+                !Object.class.equals(_cls.getSuperclass())) {
                 recordCallbacks(meta, parseCallbackMethods(_cls.getSuperclass(),
                     null, true, false, getRepository()), null, true);
             }
@@ -750,6 +756,11 @@
             meta.setDataCacheName(null);
     }
 
+    private void parseManagedInterface(ClassMetaData meta,
+        ManagedInterface iface) {
+        meta.setManagedInterface(true);
+    }
+
     /**
      * Parse @DetachedState. The annotation may be null.
      */
@@ -798,6 +809,10 @@
     public static Collection<LifecycleCallbacks>[] parseCallbackMethods
         (Class cls, Collection<LifecycleCallbacks>[] callbacks, boolean sups,
         boolean listener, MetaDataRepository repos) {
+
+        if (cls == null)
+            throw new IllegalArgumentException("cls cannot be null");
+
         // first sort / filter based on inheritance
         Set<Method> methods = new TreeSet<Method>(MethodComparator.
             getInstance());

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ManagedInterface.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ManagedInterface.java?rev=610924&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ManagedInterface.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ManagedInterface.java Thu Jan 10 12:44:35 2008
@@ -0,0 +1,41 @@
+/*
+ * 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.openjpa.persistence;
+
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * The annotated interface should be treated as a managed interface by OpenJPA.
+ * New instances of this type can be created by invoking
+ * {@link OpenJPAEntityManager#createInstance(Class)}.
+ * Interfaces with this annotation should also be annotated with one of the JPA
+ * entity annotations ({@link javax.persistence.Entity @Entity},
+ * {@link javax.persistence.MappedSuperclass @MappedSuperclass},
+ * or {@link javax.persistence.Embeddable @Embeddable}).
+ *
+ * @since 1.1.0
+ * @published
+ */
+@Target({ TYPE })
+@Retention(RUNTIME)
+public @interface ManagedInterface {
+}

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java Thu Jan 10 12:44:35 2008
@@ -77,6 +77,7 @@
     KEY_TYPE,
     LOAD_FETCH_GROUP,
     LRS,
+    MANAGED_INTERFACE,
     READ_ONLY,
     TYPE,
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java Thu Jan 10 12:44:35 2008
@@ -780,8 +780,11 @@
      * create a subclass of the type that does implement
      * {@link org.apache.openjpa.enhance.PersistenceCapable}, and will attempt
      * to redefine the methods in <code>cls</code> to enable persistent
-     * attribute tracking. Otherwise, this will return an instance of the
-     * specified class.
+     * attribute tracking. Otherwise, if <code>cls</code> is a managed type,
+     * this will return an instance of the specified class.
+     *
+     * @throws IllegalArgumentException if <code>cls</code> is not a managed
+     * type or interface.
      */
     public <T> T createInstance(Class<T> cls);
 

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java Thu Jan 10 12:44:35 2008
@@ -261,7 +261,8 @@
             J2DoPriv5Helper.getDeclaredFieldsAction(cls))))
             access |= ClassMetaData.ACCESS_FIELD;
         if (usesAccess((Method[]) AccessController.doPrivileged(
-            J2DoPriv5Helper.getDeclaredMethodsAction(cls))))
+            J2DoPriv5Helper.getDeclaredMethodsAction(cls)))
+            || cls.isInterface()) // OpenJPA managed ifaces must use prop access
             access |= ClassMetaData.ACCESS_PROPERTY;
         return (access == 0) ? getAccessType(cls.getSuperclass()) : access;
     }

Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml?rev=610924&r1=610923&r2=610924&view=diff
==============================================================================
--- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml (original)
+++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml Thu Jan 10 12:44:35 2008
@@ -483,6 +483,43 @@
             </itemizedlist>
         </section>
     </section>
+    <section id="ref_guide_pc_interfaces">
+        <title>Managed Interfaces</title>
+        <indexterm zone="ref_guide_pc_interfaces">
+            <primary>interfaces</primary>
+            <secondary>managed</secondary>
+        </indexterm>
+        <para>
+OpenJPA's managed interface feature allows you to define your object model
+entirely in terms of interfaces, instead of concrete classes. To use this
+feature, you must annotate your managed interfaces with the
+<classname>ManagedInterface</classname> annotation, and use the
+<literal>OpenJPAEntityManager.createInstance(Class)</literal> method to
+create new records. Note that <literal>createInstance()</literal> returns
+unmanaged instances; you must pass them to
+<literal>EntityManager.persist()</literal> to store them in the database.
+        </para>
+        <programlisting>
+@ManagedInterface
+public interface PersonIface {
+    @Id @GeneratedValue
+    int getId();
+    void setId(int id);
+
+    // implicitly persistent per JPA property rules
+    String getName();
+    void setName(String name);
+}
+        </programlisting>
+        <programlisting>
+OpenJPAEntityManager em = ...;
+PersonIface person = em.createInstance(PersonIface.class);
+person.setName("Homer Simpson");
+em.getTransaction().begin();
+em.persist(person);
+em.getTransaction().commit();
+        </programlisting>
+    </section>
     <section id="ref_guide_pc_oid">
         <title>
             Object Identity