mirror of https://github.com/apache/openjpa.git
OPENJPA-147 -- managed interface support. Also includes failure test case for OPENJPA-481.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@610924 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2933147f53
commit
d4a2929a57
|
@ -176,7 +176,9 @@ public class PCEnhancer {
|
|||
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 @@ public class PCEnhancer {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class PCEnhancer {
|
|||
_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 @@ public class PCEnhancer {
|
|||
|
||||
try {
|
||||
// if managed interface, skip
|
||||
if (_managedType.isInterface())
|
||||
if (_pc.isInterface())
|
||||
return ENHANCE_INTERFACE;
|
||||
|
||||
// check if already enhanced
|
||||
|
@ -526,8 +560,6 @@ public class PCEnhancer {
|
|||
} else {
|
||||
_isAlreadySubclassed = true;
|
||||
}
|
||||
} else {
|
||||
_pc = _managedType;
|
||||
}
|
||||
|
||||
_bcsConfigured = true;
|
||||
|
@ -2656,8 +2688,10 @@ public class PCEnhancer {
|
|||
}
|
||||
|
||||
// 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 @@ public class PCEnhancer {
|
|||
// 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 @@ public class PCEnhancer {
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.openjpa.lib.util.Localizer;
|
|||
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.
|
||||
|
|
|
@ -557,7 +557,11 @@ public interface Broker
|
|||
* 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);
|
||||
|
||||
|
|
|
@ -2641,8 +2641,6 @@ public class BrokerImpl
|
|||
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 class BrokerImpl
|
|||
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 @@ public class BrokerImpl
|
|||
} 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) {
|
||||
|
|
|
@ -260,8 +260,6 @@ public class StateManagerImpl
|
|||
}
|
||||
_meta = sub;
|
||||
}
|
||||
if (cls.isInterface())
|
||||
cls = _meta.getInterfaceImpl();
|
||||
|
||||
PersistenceCapable inst = PCRegistry.newInstance(cls, this, _oid, true);
|
||||
if (inst == null) {
|
||||
|
@ -814,7 +812,8 @@ public class StateManagerImpl
|
|||
|
||||
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++) {
|
||||
|
|
|
@ -180,6 +180,8 @@ public abstract class AbstractMetaDataDefaults
|
|||
*/
|
||||
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 @@ public abstract class AbstractMetaDataDefaults
|
|||
populate(fmd);
|
||||
}
|
||||
return true;
|
||||
} catch (IllegalStateException iae) {
|
||||
// thrown by registry when no metadata available
|
||||
return false;
|
||||
} catch (OpenJPAException ke) {
|
||||
throw ke;
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -732,6 +732,11 @@ public class ClassMetaData
|
|||
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 @@ public class ClassMetaData
|
|||
_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();
|
||||
|
|
|
@ -114,14 +114,13 @@ class InterfaceImplGenerator {
|
|||
// 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) {
|
||||
|
@ -229,4 +228,18 @@ class InterfaceImplGenerator {
|
|||
} 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,6 +287,11 @@ public class MetaDataRepository
|
|||
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 @@ public class MetaDataRepository
|
|||
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 @@ public class MetaDataRepository
|
|||
}
|
||||
}
|
||||
|
||||
synchronized InterfaceImplGenerator getImplGenerator() {
|
||||
if (_implGen == null)
|
||||
_implGen = new InterfaceImplGenerator(this);
|
||||
InterfaceImplGenerator getImplGenerator() {
|
||||
return _implGen;
|
||||
}
|
||||
|
||||
|
@ -1278,6 +1280,11 @@ public class MetaDataRepository
|
|||
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 class MetaDataRepository
|
|||
|
||||
public void endConfiguration() {
|
||||
initializeMetaDataFactory();
|
||||
if (_implGen == null)
|
||||
_implGen = new InterfaceImplGenerator(this);
|
||||
}
|
||||
|
||||
private void initializeMetaDataFactory() {
|
||||
|
|
|
@ -301,9 +301,7 @@ public class ApplicationIds {
|
|||
// 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();
|
||||
|
|
|
@ -388,11 +388,11 @@ multi-threaded-access: Multiple concurrent threads attempted to access a \
|
|||
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.
|
||||
an active connection to the database.
|
||||
|
|
|
@ -40,6 +40,9 @@ public class EmbedValue {
|
|||
@JoinColumn(name = "EMB_REL")
|
||||
protected EmbedOwner owner;
|
||||
|
||||
@Transient
|
||||
private int transientField;
|
||||
|
||||
public void setBasic(String basic) {
|
||||
this.basic = basic;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedClobFieldStrategy;
|
|||
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
|
||||
|
@ -78,6 +81,15 @@ public class TestEJBEmbedded extends SingleEMFTestCase {
|
|||
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() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.apache.openjpa.persistence.managedinterface;
|
||||
|
||||
|
||||
public interface NonMappedInterface {
|
||||
public int getIntField();
|
||||
|
||||
public void setIntField(int i);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -172,6 +172,7 @@ public class AnnotationPersistenceMetaDataParser
|
|||
_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 @@ public class AnnotationPersistenceMetaDataParser
|
|||
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 @@ public class AnnotationPersistenceMetaDataParser
|
|||
// 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 @@ public class AnnotationPersistenceMetaDataParser
|
|||
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 class AnnotationPersistenceMetaDataParser
|
|||
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());
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -77,6 +77,7 @@ public enum MetaDataTag {
|
|||
KEY_TYPE,
|
||||
LOAD_FETCH_GROUP,
|
||||
LRS,
|
||||
MANAGED_INTERFACE,
|
||||
READ_ONLY,
|
||||
TYPE,
|
||||
}
|
||||
|
|
|
@ -780,8 +780,11 @@ public interface OpenJPAEntityManager
|
|||
* 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);
|
||||
|
||||
|
|
|
@ -261,7 +261,8 @@ public class PersistenceMetaDataDefaults
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -483,6 +483,43 @@ a javaagent or in a Java 6 environment.
|
|||
</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
|
||||
|
|
Loading…
Reference in New Issue