mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
ADD: EntityImplements and EntityOverride + Tests
This commit is contained in:
+1
-1
@@ -49,7 +49,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>7.3</version>
|
||||
<version>7.4-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -47,7 +47,14 @@ import io.ebean.bean.PersistenceContext.WithOption;
|
||||
import io.ebean.bean.SingleBeanLoader;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.common.CopyOnFirstWriteList;
|
||||
import io.ebean.config.*;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.EncryptKeyManager;
|
||||
import io.ebean.config.QueryPlanCapture;
|
||||
import io.ebean.config.QueryPlanListener;
|
||||
import io.ebean.config.SlowQueryEvent;
|
||||
import io.ebean.config.SlowQueryListener;
|
||||
import io.ebean.config.TenantMode;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.ShutdownManager;
|
||||
@@ -649,7 +656,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
*/
|
||||
@Override
|
||||
public <T> T createEntityBean(Class<T> type) {
|
||||
return descriptor(type).createBean();
|
||||
final BeanDescriptor<T> desc = descriptor(type);
|
||||
if (desc == null) {
|
||||
throw new IllegalArgumentException("No bean type " + type.getName() + " registered");
|
||||
}
|
||||
return desc.createBean();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+101
-19
@@ -87,10 +87,11 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
private final BootupClasses bootupClasses;
|
||||
private final String serverName;
|
||||
private final List<BeanDescriptor<?>> elementDescriptors = new ArrayList<>();
|
||||
private final Map<Class<?>, BeanTable> beanTableMap = new HashMap<>();
|
||||
private final Map<String, BeanTable> beanTableMap = new HashMap<>();
|
||||
private final Map<String, BeanDescriptor<?>> descMap = new HashMap<>();
|
||||
private final Map<String, BeanDescriptor<?>> descQueueMap = new HashMap<>();
|
||||
private final Map<String, BeanManager<?>> beanManagerMap = new HashMap<>();
|
||||
private final Map<String, String> descAliases = new HashMap<>();
|
||||
private final Map<String, List<BeanDescriptor<?>>> tableToDescMap = new HashMap<>();
|
||||
private final Map<String, List<BeanDescriptor<?>>> tableToViewDescMap = new HashMap<>();
|
||||
private final DbIdentity dbIdentity;
|
||||
@@ -116,7 +117,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
private final Map<String, String> draftTableMap = new HashMap<>();
|
||||
|
||||
// temporary collections used during startup and then cleared
|
||||
private Map<Class<?>, DeployBeanInfo<?>> deployInfoMap = new HashMap<>();
|
||||
private Map<String, DeployBeanInfo<?>> deployInfoMap = new HashMap<>();
|
||||
private Set<Class<?>> embeddedIdTypes = new HashSet<>();
|
||||
private List<DeployBeanInfo<?>> embeddedBeans = new ArrayList<>();
|
||||
|
||||
@@ -234,14 +235,22 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanDescriptor<T> descriptor(Class<T> entityType) {
|
||||
return (BeanDescriptor<T>) descMap.get(entityType.getName());
|
||||
BeanDescriptor<T> ret = descriptorByClassName(entityType.getName());
|
||||
if (ret == null) {
|
||||
for (Class<?> iface : entityType.getInterfaces()) {
|
||||
ret = descriptorByClassName(iface.getName());
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanDescriptor<T> descriptorByClassName(String entityClassName) {
|
||||
return (BeanDescriptor<T>) descMap.get(entityClassName);
|
||||
return (BeanDescriptor<T>) descMap.get(resolveAlias(entityClassName));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -287,6 +296,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
try {
|
||||
createListeners();
|
||||
readEntityDeploymentInitial();
|
||||
readOverridesAndAliases();
|
||||
readXmlMapping(mappings);
|
||||
readEntityBeanTable();
|
||||
readEntityDeploymentAssociations();
|
||||
@@ -336,7 +346,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
return;
|
||||
}
|
||||
|
||||
DeployBeanInfo<?> info = deployInfoMap.get(entityClass);
|
||||
DeployBeanInfo<?> info = deploy(entityClass);
|
||||
if (info == null) {
|
||||
log.error("No entity bean for ebean.xml entry " + entityClassName);
|
||||
|
||||
@@ -550,7 +560,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
}
|
||||
|
||||
public BeanTable beanTable(Class<?> type) {
|
||||
return beanTableMap.get(type);
|
||||
return beanTableMap.get(resolveAlias(type.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -566,7 +576,12 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
}
|
||||
|
||||
private BeanManager<?> beanManager(String beanClassName) {
|
||||
return beanManagerMap.get(beanClassName);
|
||||
return beanManagerMap.get(resolveAlias(beanClassName));
|
||||
}
|
||||
|
||||
private String resolveAlias(String name) {
|
||||
String altName = descAliases.get(name);
|
||||
return altName == null ? name : altName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -591,7 +606,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> DeployBeanInfo<T> deploy(Class<T> cls) {
|
||||
return (DeployBeanInfo<T>) deployInfoMap.get(cls);
|
||||
return (DeployBeanInfo<T>) deployInfoMap.get(resolveAlias(cls.getName()));
|
||||
}
|
||||
|
||||
private void registerDescriptor(DeployBeanInfo<?> info) {
|
||||
@@ -616,7 +631,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
private void readEntityDeploymentInitial() {
|
||||
for (Class<?> entityClass : bootupClasses.getEntities()) {
|
||||
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
|
||||
deployInfoMap.put(entityClass, info);
|
||||
deployInfoMap.put(entityClass.getName(), info);
|
||||
Class<?> embeddedIdType = info.getEmbeddedIdType();
|
||||
if (embeddedIdType != null) {
|
||||
embeddedIdTypes.add(embeddedIdType);
|
||||
@@ -624,7 +639,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
}
|
||||
for (Class<?> entityClass : bootupClasses.getEmbeddables()) {
|
||||
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
|
||||
deployInfoMap.put(entityClass, info);
|
||||
deployInfoMap.put(entityClass.getName(), info);
|
||||
if (embeddedIdTypes.contains(entityClass)) {
|
||||
// register embeddedId types early - scalar properties only
|
||||
// and needed for creating BeanTables (id properties)
|
||||
@@ -650,7 +665,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
private void readEntityBeanTable() {
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
BeanTable beanTable = createBeanTable(info);
|
||||
beanTableMap.put(beanTable.getBeanType(), beanTable);
|
||||
beanTableMap.put(beanTable.getBeanType().getName(), beanTable);
|
||||
}
|
||||
// register non-id embedded beans (after bean tables are created)
|
||||
for (DeployBeanInfo<?> info : embeddedBeans) {
|
||||
@@ -674,7 +689,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
|
||||
InheritInfo inheritInfo = descriptor.getInheritInfo();
|
||||
if (inheritInfo != null && !inheritInfo.isRoot()) {
|
||||
DeployBeanInfo<?> rootBeanInfo = deployInfoMap.get(inheritInfo.getRoot().getType());
|
||||
DeployBeanInfo<?> rootBeanInfo = deploy(inheritInfo.getRoot().getType());
|
||||
PlatformIdGenerator rootIdGen = rootBeanInfo.getDescriptor().getIdGenerator();
|
||||
if (rootIdGen != null) {
|
||||
descriptor.setIdGenerator(rootIdGen);
|
||||
@@ -715,13 +730,79 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the overrides by priority. Computes a map with the base class as key
|
||||
* and the descriptor, that shoud replace that class. Modifies the deployInfoMap
|
||||
* and descAliases accordingly.
|
||||
*/
|
||||
private void readOverridesAndAliases() {
|
||||
Map<Class<?>, DeployBeanInfo<?>> overrides = new HashMap<>();
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
DeployBeanDescriptor<?> desc = info.getDescriptor();
|
||||
Integer prio = desc.getOverridePriority();
|
||||
if (prio != null) {
|
||||
Class<?> base = desc.getBaseBeanType();
|
||||
Class<?> child = desc.getBeanType();
|
||||
log.debug("{} overridden by {} with priority {}", base.getName(), child.getName(), prio);
|
||||
|
||||
// check, if we already have found an override for this base and take the one
|
||||
// with
|
||||
// lowest prio
|
||||
DeployBeanInfo<?> override = overrides.get(base);
|
||||
if (override == null) {
|
||||
overrides.put(base, info);
|
||||
} else {
|
||||
int delta = override.getDescriptor().getOverridePriority().compareTo(prio);
|
||||
if (delta > 0) {
|
||||
overrides.put(base, info);
|
||||
} else if (delta == 0) {
|
||||
throw new IllegalStateException("There are two or more implementations for " + base.getName()
|
||||
+ " with priority " + prio + ". Conflicting entity: " + desc.getBeanType().getName() + " - "
|
||||
+ override.getDescriptor().getBeanType().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
overrides.forEach((key, value) -> {
|
||||
deployInfoMap.remove(key.getName()); // remove the original descriptor
|
||||
|
||||
DeployBeanDescriptor<?> newDesc = value.getDescriptor();
|
||||
newDesc.setOverridePriority(null); // clear priority (so no discard will occur)
|
||||
|
||||
deployInfoMap.put(newDesc.getBeanType().getName(), value);
|
||||
descAliases.put(key.getName(), newDesc.getBeanType().getName());
|
||||
});
|
||||
|
||||
|
||||
// remove all left overrides classes (they are discarded)
|
||||
deployInfoMap.values().removeIf(info -> info.getDescriptor().getOverridePriority() != null);
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
for (Class<?> iface : info.getDescriptor().getInterfaces()) {
|
||||
String conflict = descAliases.put(iface.getName(), info.getDescriptor().getBeanType().getName());
|
||||
if (conflict != null) {
|
||||
throw new IllegalStateException("There are two or more implementations for " + iface
|
||||
+ ". Conflicting entity: " + conflict + " - " + info.getDescriptor().getBeanType().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// output alias map
|
||||
if (log.isInfoEnabled()) {
|
||||
descAliases.forEach((key, value) -> log.info("{} alias for {}", key, value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the inheritance info.
|
||||
*/
|
||||
private void setInheritanceInfo(DeployBeanInfo<?> info) {
|
||||
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
|
||||
if (!oneProp.isTransient()) {
|
||||
DeployBeanInfo<?> assoc = deployInfoMap.get(oneProp.getTargetType());
|
||||
DeployBeanInfo<?> assoc = deploy(oneProp.getTargetType());
|
||||
if (assoc != null) {
|
||||
oneProp.getTableJoin().setInheritInfo(assoc.getDescriptor().getInheritInfo());
|
||||
}
|
||||
@@ -729,7 +810,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
}
|
||||
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
|
||||
if (!manyProp.isTransient()) {
|
||||
DeployBeanInfo<?> assoc = deployInfoMap.get(manyProp.getTargetType());
|
||||
DeployBeanInfo<?> assoc = deploy(manyProp.getTargetType());
|
||||
if (assoc != null) {
|
||||
manyProp.getTableJoin().setInheritInfo(assoc.getDescriptor().getInheritInfo());
|
||||
}
|
||||
@@ -786,7 +867,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
|
||||
private DeployBeanDescriptor<?> targetDescriptor(DeployBeanPropertyAssoc<?> prop) {
|
||||
Class<?> targetType = prop.getTargetType();
|
||||
DeployBeanInfo<?> info = deployInfoMap.get(targetType);
|
||||
DeployBeanInfo<?> info = deploy(targetType);
|
||||
if (info == null) {
|
||||
throw new PersistenceException("Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName());
|
||||
}
|
||||
@@ -878,7 +959,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
final InheritInfo targetInheritInfo = targetDesc.getInheritInfo();
|
||||
if (targetInheritInfo != null) {
|
||||
for (InheritInfo child : targetInheritInfo.getChildren()) {
|
||||
final DeployBeanDescriptor<?> childDescriptor = deployInfoMap.get(child.getType()).getDescriptor();
|
||||
final DeployBeanDescriptor<?> childDescriptor = deploy(child.getType()).getDescriptor();
|
||||
childDescriptor.setOrderColumn(orderProperty);
|
||||
}
|
||||
}
|
||||
@@ -1143,11 +1224,12 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
// set bean controller, finder and listener
|
||||
setBeanControllerFinderListener(desc);
|
||||
deplyInherit.process(desc);
|
||||
desc.checkInheritanceMapping();
|
||||
|
||||
createProperties.createProperties(desc);
|
||||
DeployBeanInfo<T> info = new DeployBeanInfo<>(deployUtil, desc);
|
||||
readAnnotations.readInitial(info);
|
||||
|
||||
desc.checkInheritanceMapping();
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -1424,7 +1506,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
|
||||
String baseTable = prop.getDesc().getBaseTable();
|
||||
DeployTableJoin inverse = prop.getTableJoin().createInverse(baseTable);
|
||||
TableJoin inverseJoin = new TableJoin(inverse, prop.getForeignKey());
|
||||
DeployBeanInfo<?> target = deployInfoMap.get(prop.getTargetType());
|
||||
DeployBeanInfo<?> target = deploy(prop.getTargetType());
|
||||
target.setPrimaryKeyJoin(inverseJoin);
|
||||
}
|
||||
|
||||
|
||||
+51
-1
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy.meta;
|
||||
import io.ebean.annotation.Cache;
|
||||
import io.ebean.annotation.DocStore;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.EntityOverride;
|
||||
import io.ebean.annotation.Identity;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.TableName;
|
||||
@@ -16,6 +17,7 @@ import io.ebean.event.BeanPostLoad;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebean.event.changelog.ChangeLogFilter;
|
||||
import io.ebean.text.PathProperties;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.ConcurrencyMode;
|
||||
import io.ebeaninternal.server.core.CacheOptions;
|
||||
@@ -44,9 +46,11 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Describes Beans including their deployment information.
|
||||
@@ -152,6 +156,10 @@ public class DeployBeanDescriptor<T> {
|
||||
private TableJoin primaryKeyJoin;
|
||||
private Object jacksonAnnotatedClass;
|
||||
|
||||
private final Set<Class<?>> interfaces = new HashSet<>();
|
||||
|
||||
private Integer overridePriority;
|
||||
|
||||
/**
|
||||
* Construct the BeanDescriptor.
|
||||
*/
|
||||
@@ -957,7 +965,7 @@ public class DeployBeanDescriptor<T> {
|
||||
* Check the mapping for class inheritance
|
||||
*/
|
||||
public void checkInheritanceMapping() {
|
||||
if (inheritInfo == null) {
|
||||
if (inheritInfo == null && overridePriority == null) {
|
||||
checkInheritance(getBeanType());
|
||||
}
|
||||
}
|
||||
@@ -1130,4 +1138,46 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
return jacksonAnnotatedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a concrete interface, that will be registered as alias for a concrete implementation.
|
||||
*/
|
||||
public void addInterface(Class<?> iface) {
|
||||
if (!iface.isAssignableFrom(beanType)) {
|
||||
throw new ClassCastException("Cannot cast " + iface.getName() + " to " + beanType.getName());
|
||||
}
|
||||
interfaces.add(iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interfaces.
|
||||
*/
|
||||
public Set<Class<?>> getInterfaces() {
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the override priority.
|
||||
*/
|
||||
public void setOverridePriority(Integer overridePriority) {
|
||||
this.overridePriority = overridePriority;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the override priority, or null if this is a base entity.
|
||||
*/
|
||||
public Integer getOverridePriority() {
|
||||
return overridePriority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base bean type, if {@link EntityOverride} was used.
|
||||
*/
|
||||
public Class<?> getBaseBeanType() {
|
||||
Class<?> base = getBeanType();
|
||||
while (AnnotationUtil.has(base, EntityOverride.class)) {
|
||||
base = base.getSuperclass();
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import io.ebean.annotation.DbPartition;
|
||||
import io.ebean.annotation.DocStore;
|
||||
import io.ebean.annotation.Draftable;
|
||||
import io.ebean.annotation.DraftableElement;
|
||||
import io.ebean.annotation.EntityImplements;
|
||||
import io.ebean.annotation.EntityOverride;
|
||||
import io.ebean.annotation.History;
|
||||
import io.ebean.annotation.Identity;
|
||||
import io.ebean.annotation.Index;
|
||||
@@ -14,6 +16,7 @@ import io.ebean.annotation.ReadAudit;
|
||||
import io.ebean.annotation.StorageEngine;
|
||||
import io.ebean.annotation.View;
|
||||
import io.ebean.config.TableName;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.api.CoreLog;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import io.ebeaninternal.server.deploy.IndexDefinition;
|
||||
@@ -29,6 +32,7 @@ import javax.persistence.IdClass;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.ebean.util.AnnotationUtil.typeGet;
|
||||
|
||||
@@ -84,7 +88,7 @@ final class AnnotationClass extends AnnotationParser {
|
||||
*/
|
||||
private void setTableName() {
|
||||
if (descriptor.isBaseTableType()) {
|
||||
Class<?> beanType = descriptor.getBeanType();
|
||||
Class<?> beanType = descriptor.getBaseBeanType();
|
||||
InheritInfo inheritInfo = descriptor.getInheritInfo();
|
||||
if (inheritInfo != null) {
|
||||
beanType = inheritInfo.getRoot().getType();
|
||||
@@ -188,6 +192,18 @@ final class AnnotationClass extends AnnotationParser {
|
||||
for (NamedQuery namedQuery : annotationClassNamedQuery(cls)) {
|
||||
descriptor.addNamedQuery(namedQuery.name(), namedQuery.query());
|
||||
}
|
||||
|
||||
Set<EntityImplements> entityImplements = AnnotationUtil.typeGetAll(cls, EntityImplements.class);
|
||||
for (EntityImplements ann : entityImplements) {
|
||||
for (Class<?> iface : ann.value()) {
|
||||
descriptor.addInterface(iface);
|
||||
}
|
||||
}
|
||||
|
||||
EntityOverride entityOverride = AnnotationUtil.typeGet(cls, EntityOverride.class);
|
||||
if (entityOverride != null) {
|
||||
descriptor.setOverridePriority(entityOverride.priority());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import io.ebean.annotation.EntityImplements;
|
||||
import io.ebean.annotation.EntityOverride;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@Entity()
|
||||
@EntityImplements(IExtPerson1.class)
|
||||
@EntityOverride(priority = 30)
|
||||
public class ExtPerson1 extends Person implements IExtPerson1 {
|
||||
|
||||
private int myField1;
|
||||
|
||||
@Override
|
||||
public int getMyField1() {
|
||||
return myField1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMyField1(int myField1) {
|
||||
this.myField1 = myField1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import io.ebean.annotation.EntityImplements;
|
||||
import io.ebean.annotation.EntityOverride;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity()
|
||||
@Table(name = "person")
|
||||
@EntityImplements(IExtPerson2.class)
|
||||
@EntityOverride(priority = -30)
|
||||
public class ExtPerson1and2 extends ExtPerson1 implements IExtPerson2 {
|
||||
|
||||
private int myField2;
|
||||
|
||||
@Override
|
||||
public int getMyField2() {
|
||||
return myField2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMyField2(int myField2) {
|
||||
this.myField2 = myField2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import io.ebean.annotation.EntityImplements;
|
||||
import io.ebean.annotation.EntityOverride;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@EntityOverride(priority = 20)
|
||||
@EntityImplements(IExtPerson2.class)
|
||||
@Table(name = "person")
|
||||
public class ExtPerson2 extends Person implements IExtPerson2 {
|
||||
|
||||
private int myField2;
|
||||
|
||||
@Override
|
||||
public int getMyField2() {
|
||||
return myField2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMyField2(int myField2) {
|
||||
this.myField2 = myField2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
public interface IExtPerson1 extends IPerson {
|
||||
int getMyField1();
|
||||
|
||||
void setMyField1(int myField1);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
public interface IExtPerson2 extends IPerson {
|
||||
int getMyField2();
|
||||
|
||||
void setMyField2(int myField2);
|
||||
}
|
||||
@@ -5,27 +5,51 @@ import io.ebean.DB;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.tests.model.interfaces.Address;
|
||||
import org.tests.model.interfaces.ExtPerson1and2;
|
||||
import org.tests.model.interfaces.IAddress;
|
||||
import org.tests.model.interfaces.IExtPerson1;
|
||||
import org.tests.model.interfaces.IExtPerson2;
|
||||
import org.tests.model.interfaces.IPerson;
|
||||
import org.tests.model.interfaces.Person;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestManyOneInterface extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
public void testEntityOverrideEntityImplements() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
IAddress a = new Address("hello");
|
||||
IAddress a = DB.getDefault().createEntityBean(IAddress.class);
|
||||
assertThat(a).isInstanceOf(Address.class);
|
||||
|
||||
IPerson p = new Person();
|
||||
IPerson p = DB.getDefault().createEntityBean(Person.class);
|
||||
assertThat(p).isInstanceOf(ExtPerson1and2.class);
|
||||
p = DB.getDefault().getPluginApi().createEntityBean(IPerson.class);
|
||||
assertThat(p).isInstanceOf(ExtPerson1and2.class);
|
||||
|
||||
p.setDefaultAddress(a);
|
||||
|
||||
DB.save(a);
|
||||
IAddress ea1 = DB.getDefault().createEntityBean(IAddress.class);
|
||||
IAddress ea2 = DB.getDefault().createEntityBean(IAddress.class);
|
||||
|
||||
p.getExtraAddresses().add(ea1);
|
||||
p.getExtraAddresses().add(ea2);
|
||||
|
||||
DB.save(p);
|
||||
|
||||
//Assert.assertTrue();
|
||||
IAddress a2 = DB.find(IAddress.class, a.getOid());
|
||||
IPerson p2 = DB.find(IPerson.class, p.getOid());
|
||||
|
||||
assertThat(a2).isInstanceOf(Address.class);
|
||||
assertThat(p2).isNotNull().isInstanceOf(ExtPerson1and2.class);
|
||||
assertThat(p2.getDefaultAddress()).isInstanceOf(Address.class);
|
||||
|
||||
// some more checks
|
||||
IExtPerson1 pe1 = DB.getDefault().getPluginApi().createEntityBean(IExtPerson1.class);
|
||||
IExtPerson2 pe2 = DB.getDefault().getPluginApi().createEntityBean(IExtPerson2.class);
|
||||
assertThat(pe1).isInstanceOf(ExtPerson1and2.class);
|
||||
assertThat(pe2).isInstanceOf(ExtPerson1and2.class);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import io.ebean.annotation.EntityImplements;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
@EntityImplements(IAddress.class)
|
||||
public class Address implements IAddress {
|
||||
|
||||
@Id
|
||||
@@ -15,6 +19,9 @@ public class Address implements IAddress {
|
||||
|
||||
private String street;
|
||||
|
||||
@ManyToOne
|
||||
private Person extraAddress;
|
||||
|
||||
public Address(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
public interface IAddress {
|
||||
|
||||
long getOid();
|
||||
|
||||
String getStreet();
|
||||
|
||||
void setStreet(String s);
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IPerson {
|
||||
|
||||
long getOid();
|
||||
|
||||
IAddress getDefaultAddress();
|
||||
|
||||
void setDefaultAddress(IAddress address);
|
||||
|
||||
List<IAddress> getExtraAddresses();
|
||||
|
||||
List<IAddress> getAddressLinks();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package org.tests.model.interfaces;
|
||||
|
||||
import io.ebean.annotation.EntityImplements;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@EntityImplements(IPerson.class)
|
||||
public class Person implements IPerson {
|
||||
@Id
|
||||
private long oid;
|
||||
@@ -13,9 +21,15 @@ public class Person implements IPerson {
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
@ManyToOne(targetEntity = Address.class)
|
||||
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||
private IAddress defaultAddress;
|
||||
|
||||
@OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true)
|
||||
private List<IAddress> extraAddresses = new ArrayList<>();
|
||||
|
||||
@ManyToMany(cascade = CascadeType.PERSIST)
|
||||
private List<IAddress> addressLinks = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public IAddress getDefaultAddress() {
|
||||
return defaultAddress;
|
||||
@@ -42,4 +56,14 @@ public class Person implements IPerson {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IAddress> getExtraAddresses() {
|
||||
return extraAddresses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IAddress> getAddressLinks() {
|
||||
return addressLinks;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class TestTargetEntity extends BaseTestCase {
|
||||
private Person setup() {
|
||||
Address address = new Address("street");
|
||||
DB.save(address);
|
||||
Person person = new Person();
|
||||
Person person = DB.getDefault().createEntityBean(Person.class);
|
||||
person.setDefaultAddress(address);
|
||||
DB.save(person);
|
||||
return person;
|
||||
|
||||
Reference in New Issue
Block a user