mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
No effective change - change newline char
This commit is contained in:
@@ -1,122 +1,122 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
|
||||
/**
|
||||
* Persist info for determining if save or delete should be performed.
|
||||
* <p>
|
||||
* This is set to associated Beans, Table joins and List.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanCascadeInfo {
|
||||
|
||||
/**
|
||||
* should delete cascade.
|
||||
*/
|
||||
boolean delete;
|
||||
|
||||
/**
|
||||
* Should save cascade.
|
||||
*/
|
||||
boolean save;
|
||||
|
||||
/**
|
||||
* Should validate cascade.
|
||||
*/
|
||||
boolean validate;
|
||||
|
||||
/**
|
||||
* Set the raw deployment attribute.
|
||||
*/
|
||||
public void setAttribute(String attr) {
|
||||
if (attr == null){
|
||||
return;
|
||||
}
|
||||
attr = attr.toLowerCase();
|
||||
delete = (attr.indexOf("delete")>-1);
|
||||
if (!delete){
|
||||
// same as EJB3 remove
|
||||
delete = (attr.indexOf("remove")>-1);
|
||||
}
|
||||
save = (attr.indexOf("save")>-1);
|
||||
if (!save){
|
||||
// same as EJB3 persist
|
||||
save = (attr.indexOf("persist")>-1);
|
||||
}
|
||||
if (attr.indexOf("validate")>-1){
|
||||
validate = true;
|
||||
}
|
||||
|
||||
if (attr.indexOf("all")>-1){
|
||||
delete = true;
|
||||
save = true;
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTypes(CascadeType[] types) {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
setType(types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setType(CascadeType type) {
|
||||
if (type.equals(CascadeType.ALL)){
|
||||
save = true;
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.REMOVE)){
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.PERSIST)){
|
||||
save = true;
|
||||
}
|
||||
if (type.equals(CascadeType.MERGE)){
|
||||
save = true;
|
||||
}
|
||||
if (save || delete){
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if delete should cascade.
|
||||
*/
|
||||
public boolean isDelete() {
|
||||
return delete;
|
||||
}
|
||||
/**
|
||||
* Set to true if delete should cascade.
|
||||
*/
|
||||
public void setDelete(boolean isDelete) {
|
||||
this.delete = isDelete;
|
||||
}
|
||||
/**
|
||||
* Return true if save should cascade.
|
||||
*/
|
||||
public boolean isSave() {
|
||||
return save;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if save should cascade.
|
||||
*/
|
||||
public void setSave(boolean isUpdate) {
|
||||
this.save = isUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if validate should be cascaded.
|
||||
*/
|
||||
public boolean isValidate() {
|
||||
return validate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set validate to cascade or not.
|
||||
*/
|
||||
public void setValidate(boolean isValidate) {
|
||||
this.validate = isValidate;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
|
||||
/**
|
||||
* Persist info for determining if save or delete should be performed.
|
||||
* <p>
|
||||
* This is set to associated Beans, Table joins and List.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanCascadeInfo {
|
||||
|
||||
/**
|
||||
* should delete cascade.
|
||||
*/
|
||||
boolean delete;
|
||||
|
||||
/**
|
||||
* Should save cascade.
|
||||
*/
|
||||
boolean save;
|
||||
|
||||
/**
|
||||
* Should validate cascade.
|
||||
*/
|
||||
boolean validate;
|
||||
|
||||
/**
|
||||
* Set the raw deployment attribute.
|
||||
*/
|
||||
public void setAttribute(String attr) {
|
||||
if (attr == null){
|
||||
return;
|
||||
}
|
||||
attr = attr.toLowerCase();
|
||||
delete = (attr.indexOf("delete")>-1);
|
||||
if (!delete){
|
||||
// same as EJB3 remove
|
||||
delete = (attr.indexOf("remove")>-1);
|
||||
}
|
||||
save = (attr.indexOf("save")>-1);
|
||||
if (!save){
|
||||
// same as EJB3 persist
|
||||
save = (attr.indexOf("persist")>-1);
|
||||
}
|
||||
if (attr.indexOf("validate")>-1){
|
||||
validate = true;
|
||||
}
|
||||
|
||||
if (attr.indexOf("all")>-1){
|
||||
delete = true;
|
||||
save = true;
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTypes(CascadeType[] types) {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
setType(types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setType(CascadeType type) {
|
||||
if (type.equals(CascadeType.ALL)){
|
||||
save = true;
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.REMOVE)){
|
||||
delete = true;
|
||||
}
|
||||
if (type.equals(CascadeType.PERSIST)){
|
||||
save = true;
|
||||
}
|
||||
if (type.equals(CascadeType.MERGE)){
|
||||
save = true;
|
||||
}
|
||||
if (save || delete){
|
||||
validate = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if delete should cascade.
|
||||
*/
|
||||
public boolean isDelete() {
|
||||
return delete;
|
||||
}
|
||||
/**
|
||||
* Set to true if delete should cascade.
|
||||
*/
|
||||
public void setDelete(boolean isDelete) {
|
||||
this.delete = isDelete;
|
||||
}
|
||||
/**
|
||||
* Return true if save should cascade.
|
||||
*/
|
||||
public boolean isSave() {
|
||||
return save;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if save should cascade.
|
||||
*/
|
||||
public void setSave(boolean isUpdate) {
|
||||
this.save = isUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if validate should be cascaded.
|
||||
*/
|
||||
public boolean isValidate() {
|
||||
return validate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set validate to cascade or not.
|
||||
*/
|
||||
public void setValidate(boolean isValidate) {
|
||||
this.validate = isValidate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1438
-1438
File diff suppressed because it is too large
Load Diff
@@ -1,37 +1,37 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
|
||||
/**
|
||||
* Provides a method to find a BeanDescriptor.
|
||||
* <p>
|
||||
* Used during deployment of to resolve relationships between beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanDescriptorMap {
|
||||
|
||||
/**
|
||||
* Return the name of the server/database.
|
||||
*/
|
||||
public String getServerName();
|
||||
|
||||
/**
|
||||
* Return the Cache Manager.
|
||||
*/
|
||||
public ServerCacheManager getCacheManager();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for a given class.
|
||||
*/
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> entityType);
|
||||
|
||||
/**
|
||||
* Return the Encrypt key given the table and column name.
|
||||
*/
|
||||
public EncryptKey getEncryptKey(String tableName, String columnName);
|
||||
|
||||
public IdBinder createIdBinder(BeanProperty id);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
|
||||
/**
|
||||
* Provides a method to find a BeanDescriptor.
|
||||
* <p>
|
||||
* Used during deployment of to resolve relationships between beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanDescriptorMap {
|
||||
|
||||
/**
|
||||
* Return the name of the server/database.
|
||||
*/
|
||||
public String getServerName();
|
||||
|
||||
/**
|
||||
* Return the Cache Manager.
|
||||
*/
|
||||
public ServerCacheManager getCacheManager();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for a given class.
|
||||
*/
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> entityType);
|
||||
|
||||
/**
|
||||
* Return the Encrypt key given the table and column name.
|
||||
*/
|
||||
public EncryptKey getEncryptKey(String tableName, String columnName);
|
||||
|
||||
public IdBinder createIdBinder(BeanProperty id);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
public class BeanEmbeddedMeta {
|
||||
|
||||
|
||||
final BeanProperty[] properties;
|
||||
|
||||
public BeanEmbeddedMeta(BeanProperty[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties with over ridden mapping information.
|
||||
*/
|
||||
public BeanProperty[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
public class BeanEmbeddedMeta {
|
||||
|
||||
|
||||
final BeanProperty[] properties;
|
||||
|
||||
public BeanEmbeddedMeta(BeanProperty[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties with over ridden mapping information.
|
||||
*/
|
||||
public BeanProperty[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Creates BeanProperties for Embedded beans that have deployment information
|
||||
* such as the actual DB column name and table alias.
|
||||
*/
|
||||
public class BeanEmbeddedMetaFactory {
|
||||
|
||||
/**
|
||||
* Create BeanProperties for embedded beans using the deployment specific DB column name and table alias.
|
||||
*/
|
||||
public static BeanEmbeddedMeta create(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<?> prop,
|
||||
BeanDescriptor<?> descriptor) {
|
||||
|
||||
// we can get a BeanDescriptor for an Embedded bean
|
||||
// and know that it is NOT recursive, as Embedded beans are
|
||||
// only allow to hold simple scalar types...
|
||||
BeanDescriptor<?> targetDesc = owner.getBeanDescriptor(prop.getTargetType());
|
||||
if (targetDesc == null){
|
||||
String msg = "Could not find BeanDescriptor for "+prop.getTargetType()
|
||||
+". Perhaps the EmbeddedId class is not registered?";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
// deployment override information (column names)
|
||||
Map<String, String> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
|
||||
|
||||
BeanProperty[] sourceProperties = targetDesc.propertiesBaseScalar();
|
||||
|
||||
BeanProperty[] embeddedProperties = new BeanProperty[sourceProperties.length];
|
||||
|
||||
for (int i = 0; i < sourceProperties.length; i++) {
|
||||
|
||||
String propertyName = sourceProperties[i].getName();
|
||||
String dbColumn = propColMap.get(propertyName);
|
||||
if (dbColumn == null) {
|
||||
// dbColumn not overridden so take original
|
||||
dbColumn = sourceProperties[i].getDbColumn();
|
||||
}
|
||||
|
||||
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn);
|
||||
embeddedProperties[i] = new BeanProperty(sourceProperties[i], overrides);
|
||||
}
|
||||
|
||||
return new BeanEmbeddedMeta(embeddedProperties);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Creates BeanProperties for Embedded beans that have deployment information
|
||||
* such as the actual DB column name and table alias.
|
||||
*/
|
||||
public class BeanEmbeddedMetaFactory {
|
||||
|
||||
/**
|
||||
* Create BeanProperties for embedded beans using the deployment specific DB column name and table alias.
|
||||
*/
|
||||
public static BeanEmbeddedMeta create(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<?> prop,
|
||||
BeanDescriptor<?> descriptor) {
|
||||
|
||||
// we can get a BeanDescriptor for an Embedded bean
|
||||
// and know that it is NOT recursive, as Embedded beans are
|
||||
// only allow to hold simple scalar types...
|
||||
BeanDescriptor<?> targetDesc = owner.getBeanDescriptor(prop.getTargetType());
|
||||
if (targetDesc == null){
|
||||
String msg = "Could not find BeanDescriptor for "+prop.getTargetType()
|
||||
+". Perhaps the EmbeddedId class is not registered?";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
// deployment override information (column names)
|
||||
Map<String, String> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
|
||||
|
||||
BeanProperty[] sourceProperties = targetDesc.propertiesBaseScalar();
|
||||
|
||||
BeanProperty[] embeddedProperties = new BeanProperty[sourceProperties.length];
|
||||
|
||||
for (int i = 0; i < sourceProperties.length; i++) {
|
||||
|
||||
String propertyName = sourceProperties[i].getName();
|
||||
String dbColumn = propColMap.get(propertyName);
|
||||
if (dbColumn == null) {
|
||||
// dbColumn not overridden so take original
|
||||
dbColumn = sourceProperties[i].getDbColumn();
|
||||
}
|
||||
|
||||
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn);
|
||||
embeddedProperties[i] = new BeanProperty(sourceProperties[i], overrides);
|
||||
}
|
||||
|
||||
return new BeanEmbeddedMeta(embeddedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
|
||||
/**
|
||||
* Factory for controlling the construction of BeanFinders.
|
||||
*/
|
||||
public interface BeanFinderManager {
|
||||
|
||||
/**
|
||||
* Return the number of beans with a registered finder.
|
||||
*/
|
||||
public int getRegisterCount();
|
||||
|
||||
/**
|
||||
* Create the appropriate BeanController.
|
||||
*/
|
||||
public int createBeanFinders(List<Class<?>> finderClassList);
|
||||
|
||||
/**
|
||||
* Return the BeanController for a given entity type.
|
||||
*/
|
||||
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType);
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
|
||||
/**
|
||||
* Factory for controlling the construction of BeanFinders.
|
||||
*/
|
||||
public interface BeanFinderManager {
|
||||
|
||||
/**
|
||||
* Return the number of beans with a registered finder.
|
||||
*/
|
||||
public int getRegisterCount();
|
||||
|
||||
/**
|
||||
* Create the appropriate BeanController.
|
||||
*/
|
||||
public int createBeanFinders(List<Class<?>> finderClassList);
|
||||
|
||||
/**
|
||||
* Return the BeanController for a given entity type.
|
||||
*/
|
||||
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType);
|
||||
}
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
|
||||
/**
|
||||
* Represents a database foreign key which can map to an object relationship.
|
||||
*/
|
||||
public class BeanForeignKey {
|
||||
|
||||
private final String dbColumn;
|
||||
|
||||
private final int dbType;
|
||||
|
||||
/**
|
||||
* Construct the BeanForeignKey.
|
||||
*/
|
||||
public BeanForeignKey(String dbColumn, int dbType) {
|
||||
this.dbColumn = InternString.intern(dbColumn);
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database column.
|
||||
*/
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC datatype of the database column.
|
||||
*/
|
||||
public int getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof BeanForeignKey) {
|
||||
return obj.hashCode() == hashCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = getClass().hashCode();
|
||||
hc = hc * 31 + (dbColumn != null ? dbColumn.hashCode() : 0);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
|
||||
/**
|
||||
* Represents a database foreign key which can map to an object relationship.
|
||||
*/
|
||||
public class BeanForeignKey {
|
||||
|
||||
private final String dbColumn;
|
||||
|
||||
private final int dbType;
|
||||
|
||||
/**
|
||||
* Construct the BeanForeignKey.
|
||||
*/
|
||||
public BeanForeignKey(String dbColumn, int dbType) {
|
||||
this.dbColumn = InternString.intern(dbColumn);
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the database column.
|
||||
*/
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC datatype of the database column.
|
||||
*/
|
||||
public int getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof BeanForeignKey) {
|
||||
return obj.hashCode() == hashCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = getClass().hashCode();
|
||||
hc = hc * 31 + (dbColumn != null ? dbColumn.hashCode() : 0);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,151 +1,151 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.common.BeanList;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
/**
|
||||
* Helper object for dealing with Lists.
|
||||
*/
|
||||
public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
public BeanListHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
}
|
||||
|
||||
public BeanListHelp() {
|
||||
this.many = null;
|
||||
this.targetDescriptor = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal add bypassing any modify listening.
|
||||
*/
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
collection.internalAdd(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
if (bc instanceof BeanList<?>) {
|
||||
|
||||
BeanList<?> bl = (BeanList<?>) bc;
|
||||
if (bl.getActualList() == null) {
|
||||
bl.setActualList(new ArrayList<Object>());
|
||||
}
|
||||
return bl;
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanList<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmpty(EntityBean parentBean) {
|
||||
BeanList<T> beanList = new BeanList<T>(loader, parentBean, propertyName);
|
||||
if (many != null) {
|
||||
beanList.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanList<T> beanList = new BeanList<T>(loader, parentBean, propertyName);
|
||||
beanList.setModifyListening(many.getModifyListenMode());
|
||||
return beanList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
|
||||
BeanList<?> newBeanList = (BeanList<?>) server.findList(query, t);
|
||||
refresh(newBeanList, parentBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanList<?> newBeanList = (BeanList<?>) bc;
|
||||
|
||||
List<?> currentList = (List<?>) many.getValue(parentBean);
|
||||
|
||||
newBeanList.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
if (currentList == null) {
|
||||
// the currentList is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanList);
|
||||
|
||||
} else if (currentList instanceof BeanList<?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanList<?> currentBeanList = (BeanList<?>) currentList;
|
||||
currentBeanList.setActualList(newBeanList.getActualList());
|
||||
currentBeanList.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire list with the BeanList
|
||||
many.setValue(parentBean, newBeanList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
List<?> list;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
BeanList<?> beanList = (BeanList<?>) collection;
|
||||
if (!beanList.isPopulated()) {
|
||||
if (explicitInclude) {
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
beanList.size();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
list = beanList.getActualList();
|
||||
} else {
|
||||
list = (List<?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j));
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.common.BeanList;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
/**
|
||||
* Helper object for dealing with Lists.
|
||||
*/
|
||||
public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
public BeanListHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
}
|
||||
|
||||
public BeanListHelp() {
|
||||
this.many = null;
|
||||
this.targetDescriptor = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal add bypassing any modify listening.
|
||||
*/
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
collection.internalAdd(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
if (bc instanceof BeanList<?>) {
|
||||
|
||||
BeanList<?> bl = (BeanList<?>) bc;
|
||||
if (bl.getActualList() == null) {
|
||||
bl.setActualList(new ArrayList<Object>());
|
||||
}
|
||||
return bl;
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanList<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmpty(EntityBean parentBean) {
|
||||
BeanList<T> beanList = new BeanList<T>(loader, parentBean, propertyName);
|
||||
if (many != null) {
|
||||
beanList.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanList<T> beanList = new BeanList<T>(loader, parentBean, propertyName);
|
||||
beanList.setModifyListening(many.getModifyListenMode());
|
||||
return beanList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
|
||||
BeanList<?> newBeanList = (BeanList<?>) server.findList(query, t);
|
||||
refresh(newBeanList, parentBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanList<?> newBeanList = (BeanList<?>) bc;
|
||||
|
||||
List<?> currentList = (List<?>) many.getValue(parentBean);
|
||||
|
||||
newBeanList.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
if (currentList == null) {
|
||||
// the currentList is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanList);
|
||||
|
||||
} else if (currentList instanceof BeanList<?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanList<?> currentBeanList = (BeanList<?>) currentList;
|
||||
currentBeanList.setActualList(newBeanList.getActualList());
|
||||
currentBeanList.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire list with the BeanList
|
||||
many.setValue(parentBean, newBeanList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
List<?> list;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
BeanList<?> beanList = (BeanList<?>) collection;
|
||||
if (!beanList.isPopulated()) {
|
||||
if (explicitInclude) {
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
beanList.size();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
list = beanList.getActualList();
|
||||
} else {
|
||||
list = (List<?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j));
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.persist.BeanPersister;
|
||||
|
||||
/**
|
||||
* Holds the BeanDescriptor and its associated BeanPersister.
|
||||
*/
|
||||
public class BeanManager<T> {
|
||||
|
||||
private final BeanPersister persister;
|
||||
|
||||
private final BeanDescriptor<T> descriptor;
|
||||
|
||||
public BeanManager(BeanDescriptor<T> descriptor, BeanPersister persister) {
|
||||
this.descriptor = descriptor;
|
||||
this.persister = persister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated BeanPersister.
|
||||
*/
|
||||
public BeanPersister getBeanPersister() {
|
||||
return persister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor.
|
||||
*/
|
||||
public BeanDescriptor<T> getBeanDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.persist.BeanPersister;
|
||||
|
||||
/**
|
||||
* Holds the BeanDescriptor and its associated BeanPersister.
|
||||
*/
|
||||
public class BeanManager<T> {
|
||||
|
||||
private final BeanPersister persister;
|
||||
|
||||
private final BeanDescriptor<T> descriptor;
|
||||
|
||||
public BeanManager(BeanDescriptor<T> descriptor, BeanPersister persister) {
|
||||
this.descriptor = descriptor;
|
||||
this.persister = persister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated BeanPersister.
|
||||
*/
|
||||
public BeanPersister getBeanPersister() {
|
||||
return persister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor.
|
||||
*/
|
||||
public BeanDescriptor<T> getBeanDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.persist.BeanPersister;
|
||||
import com.avaje.ebeaninternal.server.persist.BeanPersisterFactory;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersisterFactory;
|
||||
|
||||
/**
|
||||
* Creates BeanManagers.
|
||||
*/
|
||||
public class BeanManagerFactory {
|
||||
|
||||
final BeanPersisterFactory peristerFactory;
|
||||
|
||||
public BeanManagerFactory(ServerConfig config, DatabasePlatform dbPlatform) {
|
||||
peristerFactory = new DmlBeanPersisterFactory(dbPlatform);
|
||||
}
|
||||
|
||||
public <T> BeanManager<T> create(BeanDescriptor<T> desc) {
|
||||
|
||||
BeanPersister persister = peristerFactory.create(desc);
|
||||
|
||||
return new BeanManager<T>(desc, persister);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.persist.BeanPersister;
|
||||
import com.avaje.ebeaninternal.server.persist.BeanPersisterFactory;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersisterFactory;
|
||||
|
||||
/**
|
||||
* Creates BeanManagers.
|
||||
*/
|
||||
public class BeanManagerFactory {
|
||||
|
||||
final BeanPersisterFactory peristerFactory;
|
||||
|
||||
public BeanManagerFactory(ServerConfig config, DatabasePlatform dbPlatform) {
|
||||
peristerFactory = new DmlBeanPersisterFactory(dbPlatform);
|
||||
}
|
||||
|
||||
public <T> BeanManager<T> create(BeanDescriptor<T> desc) {
|
||||
|
||||
BeanPersister persister = peristerFactory.create(desc);
|
||||
|
||||
return new BeanManager<T>(desc, persister);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,184 +1,184 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.common.BeanMap;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Helper specifically for dealing with Maps.
|
||||
*/
|
||||
public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
private final BeanProperty beanProperty;
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
/**
|
||||
* When created for a given query that will return a map.
|
||||
*/
|
||||
public BeanMapHelp(BeanDescriptor<T> targetDescriptor, String mapKey) {
|
||||
this.targetDescriptor = targetDescriptor;
|
||||
this.beanProperty = targetDescriptor.getBeanProperty(mapKey);
|
||||
this.many = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* When help is attached to a specific many property.
|
||||
*/ public BeanMapHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
this.beanProperty = targetDescriptor.getBeanProperty(many.getMapKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
if (mapKey == null) {
|
||||
mapKey = many.getMapKey();
|
||||
}
|
||||
BeanProperty beanProp = targetDescriptor.getBeanProperty(mapKey);
|
||||
|
||||
if (bc instanceof BeanMap<?, ?>) {
|
||||
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
|
||||
Map<Object, Object> actualMap = bm.getActualMap();
|
||||
if (actualMap == null) {
|
||||
actualMap = new LinkedHashMap<Object, Object>();
|
||||
bm.setActualMap(actualMap);
|
||||
}
|
||||
return new Adder(beanProp, actualMap);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
static class Adder implements BeanCollectionAdd {
|
||||
|
||||
private final BeanProperty beanProperty;
|
||||
|
||||
private final Map<Object, Object> map;
|
||||
|
||||
Adder(BeanProperty beanProperty, Map<Object, Object> map) {
|
||||
this.beanProperty = beanProperty;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public void addBean(EntityBean bean) {
|
||||
Object keyValue = beanProperty.getValue(bean);
|
||||
map.put(keyValue, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public BeanCollection<T> createEmpty(EntityBean ownerBean) {
|
||||
|
||||
BeanMap beanMap = new BeanMap(loader, ownerBean, propertyName);
|
||||
if (many != null) {
|
||||
beanMap.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanMap beanMap = new BeanMap(loader, parentBean, propertyName);
|
||||
if (many != null) {
|
||||
beanMap.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) server.findMap(query, t);
|
||||
refresh(newBeanMap, parentBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) bc;
|
||||
Map<?, ?> current = (Map<?, ?>) many.getValue(parentBean);
|
||||
|
||||
newBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
if (current == null) {
|
||||
// the currentMap is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
|
||||
} else if (current instanceof BeanMap<?, ?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
|
||||
currentBeanMap.setActualMap(newBeanMap.getActualMap());
|
||||
currentBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Map<?, ?> map;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
BeanMap<?, ?> bc = (BeanMap<?, ?>) collection;
|
||||
if (!bc.isPopulated()) {
|
||||
if (explicitInclude) {
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
bc.size();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = bc.getActualMap();
|
||||
} else {
|
||||
map = (Map<?, ?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (Entry<?, ?> entry : map.entrySet()) {
|
||||
//FIXME: json write map key ...
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.common.BeanMap;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Helper specifically for dealing with Maps.
|
||||
*/
|
||||
public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
private final BeanProperty beanProperty;
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
/**
|
||||
* When created for a given query that will return a map.
|
||||
*/
|
||||
public BeanMapHelp(BeanDescriptor<T> targetDescriptor, String mapKey) {
|
||||
this.targetDescriptor = targetDescriptor;
|
||||
this.beanProperty = targetDescriptor.getBeanProperty(mapKey);
|
||||
this.many = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* When help is attached to a specific many property.
|
||||
*/ public BeanMapHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
this.beanProperty = targetDescriptor.getBeanProperty(many.getMapKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
if (mapKey == null) {
|
||||
mapKey = many.getMapKey();
|
||||
}
|
||||
BeanProperty beanProp = targetDescriptor.getBeanProperty(mapKey);
|
||||
|
||||
if (bc instanceof BeanMap<?, ?>) {
|
||||
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
|
||||
Map<Object, Object> actualMap = bm.getActualMap();
|
||||
if (actualMap == null) {
|
||||
actualMap = new LinkedHashMap<Object, Object>();
|
||||
bm.setActualMap(actualMap);
|
||||
}
|
||||
return new Adder(beanProp, actualMap);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
static class Adder implements BeanCollectionAdd {
|
||||
|
||||
private final BeanProperty beanProperty;
|
||||
|
||||
private final Map<Object, Object> map;
|
||||
|
||||
Adder(BeanProperty beanProperty, Map<Object, Object> map) {
|
||||
this.beanProperty = beanProperty;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public void addBean(EntityBean bean) {
|
||||
Object keyValue = beanProperty.getValue(bean);
|
||||
map.put(keyValue, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public BeanCollection<T> createEmpty(EntityBean ownerBean) {
|
||||
|
||||
BeanMap beanMap = new BeanMap(loader, ownerBean, propertyName);
|
||||
if (many != null) {
|
||||
beanMap.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanMap beanMap = new BeanMap(loader, parentBean, propertyName);
|
||||
if (many != null) {
|
||||
beanMap.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) server.findMap(query, t);
|
||||
refresh(newBeanMap, parentBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) bc;
|
||||
Map<?, ?> current = (Map<?, ?>) many.getValue(parentBean);
|
||||
|
||||
newBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
if (current == null) {
|
||||
// the currentMap is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
|
||||
} else if (current instanceof BeanMap<?, ?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
|
||||
currentBeanMap.setActualMap(newBeanMap.getActualMap());
|
||||
currentBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Map<?, ?> map;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
BeanMap<?, ?> bc = (BeanMap<?, ?>) collection;
|
||||
if (!bc.isPopulated()) {
|
||||
if (explicitInclude) {
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
bc.size();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = bc.getActualMap();
|
||||
} else {
|
||||
map = (Map<?, ?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (Entry<?, ?> entry : map.entrySet()) {
|
||||
//FIXME: json write map key ...
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,372 +1,372 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedIdEmbedded;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedIdSimple;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Abstract base for properties mapped to an associated bean, list, set or map.
|
||||
*/
|
||||
public abstract class BeanPropertyAssoc<T> extends BeanProperty {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanPropertyAssoc.class);
|
||||
|
||||
/**
|
||||
* The descriptor of the target. This MUST be initialised after construction
|
||||
* so as to avoid a dependency loop between BeanDescriptors.
|
||||
*/
|
||||
BeanDescriptor<T> targetDescriptor;
|
||||
|
||||
IdBinder targetIdBinder;
|
||||
|
||||
InheritInfo targetInheritInfo;
|
||||
|
||||
String targetIdProperty;
|
||||
|
||||
/**
|
||||
* Persist settings.
|
||||
*/
|
||||
final BeanCascadeInfo cascadeInfo;
|
||||
|
||||
/**
|
||||
* Join between the beans.
|
||||
*/
|
||||
final TableJoin tableJoin;
|
||||
|
||||
/**
|
||||
* The type of the joined bean.
|
||||
*/
|
||||
final Class<T> targetType;
|
||||
|
||||
/**
|
||||
* The join table information.
|
||||
*/
|
||||
final BeanTable beanTable;
|
||||
|
||||
final String mappedBy;
|
||||
|
||||
/**
|
||||
* Whether the associated join type should be an outer join.
|
||||
*/
|
||||
final boolean isOuterJoin;
|
||||
|
||||
String extraWhere;
|
||||
|
||||
boolean saveRecurseSkippable;
|
||||
|
||||
boolean deleteRecurseSkippable;
|
||||
|
||||
/**
|
||||
* Construct the property.
|
||||
*/
|
||||
public BeanPropertyAssoc(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyAssoc<T> deploy) {
|
||||
super(owner, descriptor, deploy);
|
||||
this.extraWhere = InternString.intern(deploy.getExtraWhere());
|
||||
this.isOuterJoin = deploy.isOuterJoin();
|
||||
this.beanTable = deploy.getBeanTable();
|
||||
this.mappedBy = InternString.intern(deploy.getMappedBy());
|
||||
|
||||
this.tableJoin = new TableJoin(deploy.getTableJoin(), null);
|
||||
|
||||
this.targetType = deploy.getTargetType();
|
||||
this.cascadeInfo = deploy.getCascadeInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise post construction.
|
||||
*/
|
||||
@Override
|
||||
public void initialise() {
|
||||
// this *MUST* execute after the BeanDescriptor is
|
||||
// put into the map to stop infinite recursion
|
||||
if (!isTransient){
|
||||
targetDescriptor = descriptor.getBeanDescriptor(targetType);
|
||||
targetIdBinder = targetDescriptor.getIdBinder();
|
||||
targetInheritInfo = targetDescriptor.getInheritInfo();
|
||||
|
||||
saveRecurseSkippable = targetDescriptor.isSaveRecurseSkippable();
|
||||
deleteRecurseSkippable = targetDescriptor.isDeleteRecurseSkippable();
|
||||
|
||||
cascadeValidate = cascadeInfo.isValidate();
|
||||
|
||||
if (!targetIdBinder.isComplexId()){
|
||||
targetIdProperty = targetIdBinder.getIdProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ElPropertyValue for a *ToOne or *ToMany.
|
||||
*/
|
||||
protected ElPropertyValue createElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
|
||||
|
||||
// associated or embedded bean
|
||||
BeanDescriptor<?> embDesc = getTargetDescriptor();
|
||||
|
||||
if (chain == null) {
|
||||
chain = new ElPropertyChainBuilder(isEmbedded(), propName);
|
||||
}
|
||||
chain.add(this);
|
||||
if (containsMany()) {
|
||||
chain.setContainsMany(true);
|
||||
}
|
||||
return embDesc.buildElGetValue(remainder, chain, propertyDeploy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add table join with table alias based on prefix.
|
||||
*/
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) {
|
||||
return tableJoin.addJoin(joinType, prefix, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add table join with explicit table alias.
|
||||
*/
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String a1, String a2, DbSqlContext ctx) {
|
||||
return tableJoin.addJoin(joinType, a1, a2, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean isScalar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mappedBy property.
|
||||
* This will be null on the owning side.
|
||||
*/
|
||||
public String getMappedBy() {
|
||||
return mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id property of the target entity type.
|
||||
* <p>
|
||||
* This will return null for multiple Id properties.
|
||||
* </p>
|
||||
*/
|
||||
public String getTargetIdProperty() {
|
||||
return targetIdProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor of the target.
|
||||
*/
|
||||
public BeanDescriptor<T> getTargetDescriptor() {
|
||||
return targetDescriptor;
|
||||
}
|
||||
|
||||
public boolean isSaveRecurseSkippable(Object bean) {
|
||||
if (!saveRecurseSkippable){
|
||||
// we have to saveRecurse even if the bean is not dirty
|
||||
// as this bean has cascade save on some of its properties
|
||||
return false;
|
||||
}
|
||||
if (bean instanceof EntityBean){
|
||||
return !((EntityBean)bean)._ebean_getIntercept().isNewOrDirty();
|
||||
} else {
|
||||
// we don't know so we say no
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if save can be skipped for unmodified bean(s) of this
|
||||
* property.
|
||||
* <p>
|
||||
* That is, if a bean of this property is unmodified we don't need to
|
||||
* saveRecurse because none of its associated beans have cascade save set to
|
||||
* true.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isSaveRecurseSkippable() {
|
||||
return saveRecurseSkippable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to isSaveRecurseSkippable but in terms of delete.
|
||||
*/
|
||||
public boolean isDeleteRecurseSkippable() {
|
||||
return deleteRecurseSkippable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the unique id properties are all not null for this bean.
|
||||
*/
|
||||
public boolean hasId(EntityBean bean) {
|
||||
|
||||
BeanDescriptor<?> targetDesc = getTargetDescriptor();
|
||||
BeanProperty idProp = targetDesc.getIdProperty();
|
||||
if (idProp != null) {
|
||||
Object value = idProp.getValue(bean);
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// all the unique properties are non-null
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the target.
|
||||
* <p>
|
||||
* This is the class of the associated bean, or beans contained in a list,
|
||||
* set or map.
|
||||
* </p>
|
||||
*/
|
||||
public Class<?> getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an extra clause to add to the query for loading or joining
|
||||
* to this bean type.
|
||||
*/
|
||||
public String getExtraWhere() {
|
||||
return extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if this association should use an Outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return isOuterJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this association is updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
if (tableJoin.columns().length > 0) {
|
||||
return tableJoin.columns()[0].isUpdateable();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this association is insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
if (tableJoin.columns().length > 0) {
|
||||
return tableJoin.columns()[0].isInsertable();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the join to use for the bean.
|
||||
*/
|
||||
public TableJoin getTableJoin() {
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanTable for this association.
|
||||
* <p>
|
||||
* This has the table name which is used to determine the relationship for
|
||||
* this association.
|
||||
* </p>
|
||||
*/
|
||||
public BeanTable getBeanTable() {
|
||||
return beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the list of imported property. Matches BeanProperty from the target
|
||||
* descriptor back to local database columns in the TableJoin.
|
||||
*/
|
||||
protected ImportedId createImportedId(BeanPropertyAssoc<?> owner, BeanDescriptor<?> target, TableJoin join) {
|
||||
|
||||
BeanProperty idProp = target.getIdProperty();
|
||||
BeanProperty[] others = target.propertiesBaseScalar();
|
||||
|
||||
if (descriptor.isSqlSelectBased()){
|
||||
String dbColumn = owner.getDbColumn();
|
||||
return new ImportedIdSimple(owner, dbColumn, idProp, 0);
|
||||
}
|
||||
|
||||
TableJoinColumn[] cols = join.columns();
|
||||
|
||||
if (idProp == null) {
|
||||
return null;
|
||||
}
|
||||
if (!idProp.isEmbedded()) {
|
||||
// simple single scalar id
|
||||
if (cols.length != 1){
|
||||
String msg = "No Imported Id column for ["+idProp+"] in table ["+join.getTable()+"]";
|
||||
logger.error(msg);
|
||||
return null;
|
||||
} else {
|
||||
BeanProperty[] idProps = {idProp};
|
||||
return createImportedScalar(owner, cols[0], idProps, others);
|
||||
}
|
||||
} else {
|
||||
// embedded id
|
||||
BeanPropertyAssocOne<?> embProp = (BeanPropertyAssocOne<?>)idProp;
|
||||
BeanProperty[] embBaseProps = embProp.getTargetDescriptor().propertiesBaseScalar();
|
||||
ImportedIdSimple[] scalars = createImportedList(owner, cols, embBaseProps, others);
|
||||
|
||||
return new ImportedIdEmbedded(owner, embProp, scalars);
|
||||
}
|
||||
}
|
||||
|
||||
private ImportedIdSimple[] createImportedList(BeanPropertyAssoc<?> owner, TableJoinColumn[] cols, BeanProperty[] props, BeanProperty[] others) {
|
||||
|
||||
ArrayList<ImportedIdSimple> list = new ArrayList<ImportedIdSimple>();
|
||||
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
list.add(createImportedScalar(owner, cols[i], props, others));
|
||||
}
|
||||
|
||||
return ImportedIdSimple.sort(list);
|
||||
}
|
||||
|
||||
private ImportedIdSimple createImportedScalar(BeanPropertyAssoc<?> owner, TableJoinColumn col, BeanProperty[] props, BeanProperty[] others) {
|
||||
|
||||
String matchColumn = col.getForeignDbColumn();
|
||||
String localColumn = col.getLocalDbColumn();
|
||||
|
||||
for (int j = 0; j < props.length; j++) {
|
||||
if (props[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
|
||||
return new ImportedIdSimple(owner, localColumn, props[j], j);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < others.length; j++) {
|
||||
if (others[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
|
||||
return new ImportedIdSimple(owner, localColumn, others[j], j+props.length);
|
||||
}
|
||||
}
|
||||
|
||||
String msg = "Error with the Join on ["+getFullBeanName()
|
||||
+"]. Could not find the local match for ["+matchColumn+"] "//in table["+searchTable+"]?"
|
||||
+" Perhaps an error in a @JoinColumn";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedIdEmbedded;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedIdSimple;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Abstract base for properties mapped to an associated bean, list, set or map.
|
||||
*/
|
||||
public abstract class BeanPropertyAssoc<T> extends BeanProperty {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanPropertyAssoc.class);
|
||||
|
||||
/**
|
||||
* The descriptor of the target. This MUST be initialised after construction
|
||||
* so as to avoid a dependency loop between BeanDescriptors.
|
||||
*/
|
||||
BeanDescriptor<T> targetDescriptor;
|
||||
|
||||
IdBinder targetIdBinder;
|
||||
|
||||
InheritInfo targetInheritInfo;
|
||||
|
||||
String targetIdProperty;
|
||||
|
||||
/**
|
||||
* Persist settings.
|
||||
*/
|
||||
final BeanCascadeInfo cascadeInfo;
|
||||
|
||||
/**
|
||||
* Join between the beans.
|
||||
*/
|
||||
final TableJoin tableJoin;
|
||||
|
||||
/**
|
||||
* The type of the joined bean.
|
||||
*/
|
||||
final Class<T> targetType;
|
||||
|
||||
/**
|
||||
* The join table information.
|
||||
*/
|
||||
final BeanTable beanTable;
|
||||
|
||||
final String mappedBy;
|
||||
|
||||
/**
|
||||
* Whether the associated join type should be an outer join.
|
||||
*/
|
||||
final boolean isOuterJoin;
|
||||
|
||||
String extraWhere;
|
||||
|
||||
boolean saveRecurseSkippable;
|
||||
|
||||
boolean deleteRecurseSkippable;
|
||||
|
||||
/**
|
||||
* Construct the property.
|
||||
*/
|
||||
public BeanPropertyAssoc(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyAssoc<T> deploy) {
|
||||
super(owner, descriptor, deploy);
|
||||
this.extraWhere = InternString.intern(deploy.getExtraWhere());
|
||||
this.isOuterJoin = deploy.isOuterJoin();
|
||||
this.beanTable = deploy.getBeanTable();
|
||||
this.mappedBy = InternString.intern(deploy.getMappedBy());
|
||||
|
||||
this.tableJoin = new TableJoin(deploy.getTableJoin(), null);
|
||||
|
||||
this.targetType = deploy.getTargetType();
|
||||
this.cascadeInfo = deploy.getCascadeInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise post construction.
|
||||
*/
|
||||
@Override
|
||||
public void initialise() {
|
||||
// this *MUST* execute after the BeanDescriptor is
|
||||
// put into the map to stop infinite recursion
|
||||
if (!isTransient){
|
||||
targetDescriptor = descriptor.getBeanDescriptor(targetType);
|
||||
targetIdBinder = targetDescriptor.getIdBinder();
|
||||
targetInheritInfo = targetDescriptor.getInheritInfo();
|
||||
|
||||
saveRecurseSkippable = targetDescriptor.isSaveRecurseSkippable();
|
||||
deleteRecurseSkippable = targetDescriptor.isDeleteRecurseSkippable();
|
||||
|
||||
cascadeValidate = cascadeInfo.isValidate();
|
||||
|
||||
if (!targetIdBinder.isComplexId()){
|
||||
targetIdProperty = targetIdBinder.getIdProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ElPropertyValue for a *ToOne or *ToMany.
|
||||
*/
|
||||
protected ElPropertyValue createElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
|
||||
|
||||
// associated or embedded bean
|
||||
BeanDescriptor<?> embDesc = getTargetDescriptor();
|
||||
|
||||
if (chain == null) {
|
||||
chain = new ElPropertyChainBuilder(isEmbedded(), propName);
|
||||
}
|
||||
chain.add(this);
|
||||
if (containsMany()) {
|
||||
chain.setContainsMany(true);
|
||||
}
|
||||
return embDesc.buildElGetValue(remainder, chain, propertyDeploy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add table join with table alias based on prefix.
|
||||
*/
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) {
|
||||
return tableJoin.addJoin(joinType, prefix, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add table join with explicit table alias.
|
||||
*/
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String a1, String a2, DbSqlContext ctx) {
|
||||
return tableJoin.addJoin(joinType, a1, a2, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean isScalar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mappedBy property.
|
||||
* This will be null on the owning side.
|
||||
*/
|
||||
public String getMappedBy() {
|
||||
return mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id property of the target entity type.
|
||||
* <p>
|
||||
* This will return null for multiple Id properties.
|
||||
* </p>
|
||||
*/
|
||||
public String getTargetIdProperty() {
|
||||
return targetIdProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor of the target.
|
||||
*/
|
||||
public BeanDescriptor<T> getTargetDescriptor() {
|
||||
return targetDescriptor;
|
||||
}
|
||||
|
||||
public boolean isSaveRecurseSkippable(Object bean) {
|
||||
if (!saveRecurseSkippable){
|
||||
// we have to saveRecurse even if the bean is not dirty
|
||||
// as this bean has cascade save on some of its properties
|
||||
return false;
|
||||
}
|
||||
if (bean instanceof EntityBean){
|
||||
return !((EntityBean)bean)._ebean_getIntercept().isNewOrDirty();
|
||||
} else {
|
||||
// we don't know so we say no
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if save can be skipped for unmodified bean(s) of this
|
||||
* property.
|
||||
* <p>
|
||||
* That is, if a bean of this property is unmodified we don't need to
|
||||
* saveRecurse because none of its associated beans have cascade save set to
|
||||
* true.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isSaveRecurseSkippable() {
|
||||
return saveRecurseSkippable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to isSaveRecurseSkippable but in terms of delete.
|
||||
*/
|
||||
public boolean isDeleteRecurseSkippable() {
|
||||
return deleteRecurseSkippable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the unique id properties are all not null for this bean.
|
||||
*/
|
||||
public boolean hasId(EntityBean bean) {
|
||||
|
||||
BeanDescriptor<?> targetDesc = getTargetDescriptor();
|
||||
BeanProperty idProp = targetDesc.getIdProperty();
|
||||
if (idProp != null) {
|
||||
Object value = idProp.getValue(bean);
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// all the unique properties are non-null
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the target.
|
||||
* <p>
|
||||
* This is the class of the associated bean, or beans contained in a list,
|
||||
* set or map.
|
||||
* </p>
|
||||
*/
|
||||
public Class<?> getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an extra clause to add to the query for loading or joining
|
||||
* to this bean type.
|
||||
*/
|
||||
public String getExtraWhere() {
|
||||
return extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if this association should use an Outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return isOuterJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this association is updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
if (tableJoin.columns().length > 0) {
|
||||
return tableJoin.columns()[0].isUpdateable();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this association is insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
if (tableJoin.columns().length > 0) {
|
||||
return tableJoin.columns()[0].isInsertable();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the join to use for the bean.
|
||||
*/
|
||||
public TableJoin getTableJoin() {
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanTable for this association.
|
||||
* <p>
|
||||
* This has the table name which is used to determine the relationship for
|
||||
* this association.
|
||||
* </p>
|
||||
*/
|
||||
public BeanTable getBeanTable() {
|
||||
return beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the list of imported property. Matches BeanProperty from the target
|
||||
* descriptor back to local database columns in the TableJoin.
|
||||
*/
|
||||
protected ImportedId createImportedId(BeanPropertyAssoc<?> owner, BeanDescriptor<?> target, TableJoin join) {
|
||||
|
||||
BeanProperty idProp = target.getIdProperty();
|
||||
BeanProperty[] others = target.propertiesBaseScalar();
|
||||
|
||||
if (descriptor.isSqlSelectBased()){
|
||||
String dbColumn = owner.getDbColumn();
|
||||
return new ImportedIdSimple(owner, dbColumn, idProp, 0);
|
||||
}
|
||||
|
||||
TableJoinColumn[] cols = join.columns();
|
||||
|
||||
if (idProp == null) {
|
||||
return null;
|
||||
}
|
||||
if (!idProp.isEmbedded()) {
|
||||
// simple single scalar id
|
||||
if (cols.length != 1){
|
||||
String msg = "No Imported Id column for ["+idProp+"] in table ["+join.getTable()+"]";
|
||||
logger.error(msg);
|
||||
return null;
|
||||
} else {
|
||||
BeanProperty[] idProps = {idProp};
|
||||
return createImportedScalar(owner, cols[0], idProps, others);
|
||||
}
|
||||
} else {
|
||||
// embedded id
|
||||
BeanPropertyAssocOne<?> embProp = (BeanPropertyAssocOne<?>)idProp;
|
||||
BeanProperty[] embBaseProps = embProp.getTargetDescriptor().propertiesBaseScalar();
|
||||
ImportedIdSimple[] scalars = createImportedList(owner, cols, embBaseProps, others);
|
||||
|
||||
return new ImportedIdEmbedded(owner, embProp, scalars);
|
||||
}
|
||||
}
|
||||
|
||||
private ImportedIdSimple[] createImportedList(BeanPropertyAssoc<?> owner, TableJoinColumn[] cols, BeanProperty[] props, BeanProperty[] others) {
|
||||
|
||||
ArrayList<ImportedIdSimple> list = new ArrayList<ImportedIdSimple>();
|
||||
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
list.add(createImportedScalar(owner, cols[i], props, others));
|
||||
}
|
||||
|
||||
return ImportedIdSimple.sort(list);
|
||||
}
|
||||
|
||||
private ImportedIdSimple createImportedScalar(BeanPropertyAssoc<?> owner, TableJoinColumn col, BeanProperty[] props, BeanProperty[] others) {
|
||||
|
||||
String matchColumn = col.getForeignDbColumn();
|
||||
String localColumn = col.getLocalDbColumn();
|
||||
|
||||
for (int j = 0; j < props.length; j++) {
|
||||
if (props[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
|
||||
return new ImportedIdSimple(owner, localColumn, props[j], j);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < others.length; j++) {
|
||||
if (others[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
|
||||
return new ImportedIdSimple(owner, localColumn, others[j], j+props.length);
|
||||
}
|
||||
}
|
||||
|
||||
String msg = "Error with the Join on ["+getFullBeanName()
|
||||
+"]. Could not find the local match for ["+matchColumn+"] "//in table["+searchTable+"]?"
|
||||
+" Perhaps an error in a @JoinColumn";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,198 +1,198 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebean.text.json.EJson;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundPropertyElAdapter;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
/**
|
||||
* Property mapped to an Immutable Compound Value Object.
|
||||
* <p>
|
||||
* An Immutable Compound Value Object is similar to an Embedded bean but it
|
||||
* doesn't require enhancement and MUST be treated as an Immutable type.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPropertyCompound extends BeanProperty {
|
||||
|
||||
private final CtCompoundType<?> compoundType;
|
||||
|
||||
/**
|
||||
* Type Converter for scala.Option and similar type wrapping.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final ScalarTypeConverter typeConverter;
|
||||
|
||||
private final BeanProperty[] scalarProperties;
|
||||
|
||||
private final LinkedHashMap<String, BeanProperty> propertyMap = new LinkedHashMap<String, BeanProperty>();
|
||||
|
||||
private final LinkedHashMap<String, CtCompoundPropertyElAdapter> nonScalarMap = new LinkedHashMap<String, CtCompoundPropertyElAdapter>();
|
||||
|
||||
private final BeanPropertyCompoundRoot root;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public BeanPropertyCompound(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyCompound deploy) {
|
||||
|
||||
super(owner, descriptor, deploy);
|
||||
|
||||
this.compoundType = deploy.getCompoundType();
|
||||
this.typeConverter = deploy.getTypeConverter();
|
||||
|
||||
this.root = deploy.getFlatProperties(owner, descriptor);
|
||||
|
||||
this.scalarProperties = root.getScalarProperties();
|
||||
|
||||
for (int i = 0; i < scalarProperties.length; i++) {
|
||||
propertyMap.put(scalarProperties[i].getName(), scalarProperties[i]);
|
||||
}
|
||||
|
||||
List<CtCompoundProperty> nonScalarPropsList = root.getNonScalarProperties();
|
||||
|
||||
for (int i = 0; i < nonScalarPropsList.size(); i++) {
|
||||
CtCompoundProperty ctProp = nonScalarPropsList.get(i);
|
||||
CtCompoundPropertyElAdapter adapter = new CtCompoundPropertyElAdapter(ctProp);
|
||||
nonScalarMap.put(ctProp.getRelativeName(), adapter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialise() {
|
||||
// do nothing for normal BeanProperty
|
||||
if (!isTransient && compoundType == null) {
|
||||
String msg = "No cvoInternalType assigned to " + descriptor.getFullName() + "." + getName();
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeployOrder(int deployOrder) {
|
||||
this.deployOrder = deployOrder;
|
||||
for (CtCompoundPropertyElAdapter adapter : nonScalarMap.values()) {
|
||||
adapter.setDeployOrder(deployOrder);
|
||||
}
|
||||
}
|
||||
|
||||
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
|
||||
|
||||
if (chain == null) {
|
||||
chain = new ElPropertyChainBuilder(true, propName);
|
||||
}
|
||||
|
||||
// first add this property
|
||||
chain.add(this);
|
||||
|
||||
// handle all the rest of the chain handled by the
|
||||
// BeanProperty (all depth for nested compound type)
|
||||
BeanProperty p = propertyMap.get(remainder);
|
||||
if (p != null) {
|
||||
return chain.add(p).build();
|
||||
}
|
||||
CtCompoundPropertyElAdapter elAdapter = nonScalarMap.get(remainder);
|
||||
if (elAdapter == null) {
|
||||
throw new RuntimeException("property [" + remainder + "] not found in " + getFullBeanName());
|
||||
}
|
||||
return chain.add(elAdapter).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
if (!isTransient) {
|
||||
for (int i = 0; i < scalarProperties.length; i++) {
|
||||
scalarProperties[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BeanProperty[] getScalarProperties() {
|
||||
return scalarProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
|
||||
|
||||
boolean assignable = (type == null || owningType.isAssignableFrom(type));
|
||||
|
||||
Object v = compoundType.read(ctx.getDataReader());
|
||||
if (assignable) {
|
||||
setValue(bean, v);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the data from the resultSet effectively ignoring it and returning
|
||||
* null.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
Object v = compoundType.read(ctx.getDataReader());
|
||||
if (typeConverter != null){
|
||||
v = typeConverter.wrapValue(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
compoundType.loadIgnore(ctx.getDataReader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
|
||||
sqlBeanLoad.load(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
Object value = getValueIntercept(bean);
|
||||
if (value == null) {
|
||||
ctx.writeNull(name);
|
||||
} else {
|
||||
compoundType.jsonWrite(ctx, value, name);
|
||||
}
|
||||
}
|
||||
|
||||
public void jsonRead(JsonParser ctx, EntityBean bean) throws IOException {
|
||||
|
||||
if (!jsonDeserialize) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object value = EJson.parse(ctx);
|
||||
if (value == null) {
|
||||
setValue(bean, null);
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,Object> map = (Map<String,Object>)value;
|
||||
Object objValue = compoundType.jsonConvert(map);
|
||||
setValue(bean, objValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebean.text.json.EJson;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundPropertyElAdapter;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
/**
|
||||
* Property mapped to an Immutable Compound Value Object.
|
||||
* <p>
|
||||
* An Immutable Compound Value Object is similar to an Embedded bean but it
|
||||
* doesn't require enhancement and MUST be treated as an Immutable type.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPropertyCompound extends BeanProperty {
|
||||
|
||||
private final CtCompoundType<?> compoundType;
|
||||
|
||||
/**
|
||||
* Type Converter for scala.Option and similar type wrapping.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final ScalarTypeConverter typeConverter;
|
||||
|
||||
private final BeanProperty[] scalarProperties;
|
||||
|
||||
private final LinkedHashMap<String, BeanProperty> propertyMap = new LinkedHashMap<String, BeanProperty>();
|
||||
|
||||
private final LinkedHashMap<String, CtCompoundPropertyElAdapter> nonScalarMap = new LinkedHashMap<String, CtCompoundPropertyElAdapter>();
|
||||
|
||||
private final BeanPropertyCompoundRoot root;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public BeanPropertyCompound(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyCompound deploy) {
|
||||
|
||||
super(owner, descriptor, deploy);
|
||||
|
||||
this.compoundType = deploy.getCompoundType();
|
||||
this.typeConverter = deploy.getTypeConverter();
|
||||
|
||||
this.root = deploy.getFlatProperties(owner, descriptor);
|
||||
|
||||
this.scalarProperties = root.getScalarProperties();
|
||||
|
||||
for (int i = 0; i < scalarProperties.length; i++) {
|
||||
propertyMap.put(scalarProperties[i].getName(), scalarProperties[i]);
|
||||
}
|
||||
|
||||
List<CtCompoundProperty> nonScalarPropsList = root.getNonScalarProperties();
|
||||
|
||||
for (int i = 0; i < nonScalarPropsList.size(); i++) {
|
||||
CtCompoundProperty ctProp = nonScalarPropsList.get(i);
|
||||
CtCompoundPropertyElAdapter adapter = new CtCompoundPropertyElAdapter(ctProp);
|
||||
nonScalarMap.put(ctProp.getRelativeName(), adapter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialise() {
|
||||
// do nothing for normal BeanProperty
|
||||
if (!isTransient && compoundType == null) {
|
||||
String msg = "No cvoInternalType assigned to " + descriptor.getFullName() + "." + getName();
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeployOrder(int deployOrder) {
|
||||
this.deployOrder = deployOrder;
|
||||
for (CtCompoundPropertyElAdapter adapter : nonScalarMap.values()) {
|
||||
adapter.setDeployOrder(deployOrder);
|
||||
}
|
||||
}
|
||||
|
||||
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
|
||||
|
||||
if (chain == null) {
|
||||
chain = new ElPropertyChainBuilder(true, propName);
|
||||
}
|
||||
|
||||
// first add this property
|
||||
chain.add(this);
|
||||
|
||||
// handle all the rest of the chain handled by the
|
||||
// BeanProperty (all depth for nested compound type)
|
||||
BeanProperty p = propertyMap.get(remainder);
|
||||
if (p != null) {
|
||||
return chain.add(p).build();
|
||||
}
|
||||
CtCompoundPropertyElAdapter elAdapter = nonScalarMap.get(remainder);
|
||||
if (elAdapter == null) {
|
||||
throw new RuntimeException("property [" + remainder + "] not found in " + getFullBeanName());
|
||||
}
|
||||
return chain.add(elAdapter).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
if (!isTransient) {
|
||||
for (int i = 0; i < scalarProperties.length; i++) {
|
||||
scalarProperties[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BeanProperty[] getScalarProperties() {
|
||||
return scalarProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
|
||||
|
||||
boolean assignable = (type == null || owningType.isAssignableFrom(type));
|
||||
|
||||
Object v = compoundType.read(ctx.getDataReader());
|
||||
if (assignable) {
|
||||
setValue(bean, v);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the data from the resultSet effectively ignoring it and returning
|
||||
* null.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
Object v = compoundType.read(ctx.getDataReader());
|
||||
if (typeConverter != null){
|
||||
v = typeConverter.wrapValue(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
compoundType.loadIgnore(ctx.getDataReader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
|
||||
sqlBeanLoad.load(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
Object value = getValueIntercept(bean);
|
||||
if (value == null) {
|
||||
ctx.writeNull(name);
|
||||
} else {
|
||||
compoundType.jsonWrite(ctx, value, name);
|
||||
}
|
||||
}
|
||||
|
||||
public void jsonRead(JsonParser ctx, EntityBean bean) throws IOException {
|
||||
|
||||
if (!jsonDeserialize) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object value = EJson.parse(ctx);
|
||||
if (value == null) {
|
||||
setValue(bean, null);
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,Object> map = (Map<String,Object>)value;
|
||||
Object objValue = compoundType.jsonConvert(map);
|
||||
setValue(bean, objValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+110
-110
@@ -1,110 +1,110 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertySetter;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
|
||||
/**
|
||||
* Represents the root BeanProperty for properties of a compound type.
|
||||
* <p>
|
||||
* Holds all the scalar and non-scalar properties of the compound type. The
|
||||
* scalar properties match to DB columns and the non-scalar ones are here solely
|
||||
* to support EL expression language for nested compound types.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class BeanPropertyCompoundRoot {
|
||||
|
||||
private final BeanPropertySetter setter;
|
||||
|
||||
/**
|
||||
* The method used to write the property.
|
||||
*/
|
||||
private final Method writeMethod;
|
||||
|
||||
private final String name;
|
||||
private final String fullBeanName;
|
||||
|
||||
private final LinkedHashMap<String, BeanPropertyCompoundScalar> propMap;
|
||||
|
||||
private final ArrayList<BeanPropertyCompoundScalar> propList;
|
||||
|
||||
private List<CtCompoundProperty> nonScalarProperties;
|
||||
|
||||
public BeanPropertyCompoundRoot(DeployBeanProperty deploy) {
|
||||
this.fullBeanName = deploy.getFullBeanName();
|
||||
this.name = deploy.getName();
|
||||
this.setter = deploy.getSetter();
|
||||
this.writeMethod = deploy.getWriteMethod();
|
||||
this.propList = new ArrayList<BeanPropertyCompoundScalar>();
|
||||
this.propMap = new LinkedHashMap<String, BeanPropertyCompoundScalar>();
|
||||
}
|
||||
|
||||
public BeanProperty[] getScalarProperties() {
|
||||
|
||||
return propList.toArray(new BeanProperty[propList.size()]);
|
||||
}
|
||||
|
||||
public void register(BeanPropertyCompoundScalar prop) {
|
||||
propList.add(prop);
|
||||
propMap.put(prop.getName(), prop);
|
||||
}
|
||||
|
||||
public BeanPropertyCompoundScalar getCompoundScalarProperty(String propName) {
|
||||
return propMap.get(propName);
|
||||
}
|
||||
|
||||
public List<CtCompoundProperty> getNonScalarProperties() {
|
||||
return nonScalarProperties;
|
||||
}
|
||||
|
||||
public void setNonScalarProperties(List<CtCompoundProperty> nonScalarProperties) {
|
||||
this.nonScalarProperties = nonScalarProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the property without interception or
|
||||
* PropertyChangeSupport.
|
||||
*/
|
||||
public void setRootValue(EntityBean bean, Object value) {
|
||||
try {
|
||||
if (bean instanceof EntityBean) {
|
||||
setter.set(bean, value);
|
||||
} else {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = value;
|
||||
writeMethod.invoke(bean, args);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "set " + name + " with arg[" + value + "] on ["+fullBeanName+"] with type[" + beanType + "] threw error";
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the property.
|
||||
*/
|
||||
public void setRootValueIntercept(EntityBean bean, Object value) {
|
||||
try {
|
||||
if (bean instanceof EntityBean) {
|
||||
setter.setIntercept(bean, value);
|
||||
} else {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = value;
|
||||
writeMethod.invoke(bean, args);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "setIntercept " + name + " arg[" + value + "] on ["+fullBeanName+"] with type[" + beanType + "] threw error";
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertySetter;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
|
||||
/**
|
||||
* Represents the root BeanProperty for properties of a compound type.
|
||||
* <p>
|
||||
* Holds all the scalar and non-scalar properties of the compound type. The
|
||||
* scalar properties match to DB columns and the non-scalar ones are here solely
|
||||
* to support EL expression language for nested compound types.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class BeanPropertyCompoundRoot {
|
||||
|
||||
private final BeanPropertySetter setter;
|
||||
|
||||
/**
|
||||
* The method used to write the property.
|
||||
*/
|
||||
private final Method writeMethod;
|
||||
|
||||
private final String name;
|
||||
private final String fullBeanName;
|
||||
|
||||
private final LinkedHashMap<String, BeanPropertyCompoundScalar> propMap;
|
||||
|
||||
private final ArrayList<BeanPropertyCompoundScalar> propList;
|
||||
|
||||
private List<CtCompoundProperty> nonScalarProperties;
|
||||
|
||||
public BeanPropertyCompoundRoot(DeployBeanProperty deploy) {
|
||||
this.fullBeanName = deploy.getFullBeanName();
|
||||
this.name = deploy.getName();
|
||||
this.setter = deploy.getSetter();
|
||||
this.writeMethod = deploy.getWriteMethod();
|
||||
this.propList = new ArrayList<BeanPropertyCompoundScalar>();
|
||||
this.propMap = new LinkedHashMap<String, BeanPropertyCompoundScalar>();
|
||||
}
|
||||
|
||||
public BeanProperty[] getScalarProperties() {
|
||||
|
||||
return propList.toArray(new BeanProperty[propList.size()]);
|
||||
}
|
||||
|
||||
public void register(BeanPropertyCompoundScalar prop) {
|
||||
propList.add(prop);
|
||||
propMap.put(prop.getName(), prop);
|
||||
}
|
||||
|
||||
public BeanPropertyCompoundScalar getCompoundScalarProperty(String propName) {
|
||||
return propMap.get(propName);
|
||||
}
|
||||
|
||||
public List<CtCompoundProperty> getNonScalarProperties() {
|
||||
return nonScalarProperties;
|
||||
}
|
||||
|
||||
public void setNonScalarProperties(List<CtCompoundProperty> nonScalarProperties) {
|
||||
this.nonScalarProperties = nonScalarProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the property without interception or
|
||||
* PropertyChangeSupport.
|
||||
*/
|
||||
public void setRootValue(EntityBean bean, Object value) {
|
||||
try {
|
||||
if (bean instanceof EntityBean) {
|
||||
setter.set(bean, value);
|
||||
} else {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = value;
|
||||
writeMethod.invoke(bean, args);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "set " + name + " with arg[" + value + "] on ["+fullBeanName+"] with type[" + beanType + "] threw error";
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the property.
|
||||
*/
|
||||
public void setRootValueIntercept(EntityBean bean, Object value) {
|
||||
try {
|
||||
if (bean instanceof EntityBean) {
|
||||
setter.setIntercept(bean, value);
|
||||
} else {
|
||||
Object[] args = new Object[1];
|
||||
args[0] = value;
|
||||
writeMethod.invoke(bean, args);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "setIntercept " + name + " arg[" + value + "] on ["+fullBeanName+"] with type[" + beanType + "] threw error";
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+105
-105
@@ -1,105 +1,105 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
|
||||
/**
|
||||
* A BeanProperty owned by a Compound value object that maps to
|
||||
* a real scalar type.
|
||||
*/
|
||||
public class BeanPropertyCompoundScalar extends BeanProperty {
|
||||
|
||||
private final BeanPropertyCompoundRoot rootProperty;
|
||||
|
||||
private final CtCompoundProperty ctProperty;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final ScalarTypeConverter typeConverter;
|
||||
|
||||
public BeanPropertyCompoundScalar(BeanPropertyCompoundRoot rootProperty, DeployBeanProperty scalarDeploy,
|
||||
CtCompoundProperty ctProperty, ScalarTypeConverter<?, ?> typeConverter) {
|
||||
|
||||
super(scalarDeploy);
|
||||
this.rootProperty = rootProperty;
|
||||
this.ctProperty = ctProperty;
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return one of the scalar values from a compound type.
|
||||
*/
|
||||
public Object getValueObject(Object compoundValue) {
|
||||
if (typeConverter != null) {
|
||||
compoundValue = typeConverter.unwrapValue(compoundValue);
|
||||
}
|
||||
return ctProperty.getValue(compoundValue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object getValue(EntityBean valueObject) {
|
||||
Object val = valueObject;
|
||||
if (typeConverter != null) {
|
||||
val = typeConverter.unwrapValue(val);
|
||||
}
|
||||
return ctProperty.getValue(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EntityBean bean, Object value) {
|
||||
setValueInCompound(bean, value, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setValueInCompound(EntityBean bean, Object value, boolean intercept) {
|
||||
|
||||
Object compoundValue = ctProperty.setValue(bean, value);
|
||||
|
||||
if (compoundValue != null) {
|
||||
if (typeConverter != null) {
|
||||
compoundValue = typeConverter.wrapValue(compoundValue);
|
||||
}
|
||||
// we are at the top level and we have a compound value
|
||||
// that we can set using the root property
|
||||
if (intercept) {
|
||||
rootProperty.setRootValueIntercept(bean, compoundValue);
|
||||
} else {
|
||||
rootProperty.setRootValue(bean, compoundValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No interception on embedded scalar values inside a CVO.
|
||||
*/
|
||||
@Override
|
||||
public void setValueIntercept(EntityBean bean, Object value) {
|
||||
setValueInCompound(bean, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* No interception on embedded scalar values inside a CVO.
|
||||
*/
|
||||
@Override
|
||||
public Object getValueIntercept(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void elSetValue(EntityBean bean, Object value, boolean populate) {//, boolean reference) {
|
||||
super.elSetValue(bean, value, populate);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
|
||||
/**
|
||||
* A BeanProperty owned by a Compound value object that maps to
|
||||
* a real scalar type.
|
||||
*/
|
||||
public class BeanPropertyCompoundScalar extends BeanProperty {
|
||||
|
||||
private final BeanPropertyCompoundRoot rootProperty;
|
||||
|
||||
private final CtCompoundProperty ctProperty;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final ScalarTypeConverter typeConverter;
|
||||
|
||||
public BeanPropertyCompoundScalar(BeanPropertyCompoundRoot rootProperty, DeployBeanProperty scalarDeploy,
|
||||
CtCompoundProperty ctProperty, ScalarTypeConverter<?, ?> typeConverter) {
|
||||
|
||||
super(scalarDeploy);
|
||||
this.rootProperty = rootProperty;
|
||||
this.ctProperty = ctProperty;
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return one of the scalar values from a compound type.
|
||||
*/
|
||||
public Object getValueObject(Object compoundValue) {
|
||||
if (typeConverter != null) {
|
||||
compoundValue = typeConverter.unwrapValue(compoundValue);
|
||||
}
|
||||
return ctProperty.getValue(compoundValue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object getValue(EntityBean valueObject) {
|
||||
Object val = valueObject;
|
||||
if (typeConverter != null) {
|
||||
val = typeConverter.unwrapValue(val);
|
||||
}
|
||||
return ctProperty.getValue(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EntityBean bean, Object value) {
|
||||
setValueInCompound(bean, value, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setValueInCompound(EntityBean bean, Object value, boolean intercept) {
|
||||
|
||||
Object compoundValue = ctProperty.setValue(bean, value);
|
||||
|
||||
if (compoundValue != null) {
|
||||
if (typeConverter != null) {
|
||||
compoundValue = typeConverter.wrapValue(compoundValue);
|
||||
}
|
||||
// we are at the top level and we have a compound value
|
||||
// that we can set using the root property
|
||||
if (intercept) {
|
||||
rootProperty.setRootValueIntercept(bean, compoundValue);
|
||||
} else {
|
||||
rootProperty.setRootValue(bean, compoundValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No interception on embedded scalar values inside a CVO.
|
||||
*/
|
||||
@Override
|
||||
public void setValueIntercept(EntityBean bean, Object value) {
|
||||
setValueInCompound(bean, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* No interception on embedded scalar values inside a CVO.
|
||||
*/
|
||||
@Override
|
||||
public Object getValueIntercept(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void elSetValue(EntityBean bean, Object value, boolean populate) {//, boolean reference) {
|
||||
super.elSetValue(bean, value, populate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
|
||||
/**
|
||||
* Used hold meta data when a bean property is overridden.
|
||||
* <p>
|
||||
* Typically this is for Embedded Beans.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPropertyOverride {
|
||||
|
||||
private final String dbColumn;
|
||||
|
||||
private final String sqlFormulaSelect;
|
||||
|
||||
private final String sqlFormulaJoin;
|
||||
|
||||
public BeanPropertyOverride(String dbColumn) {
|
||||
this(dbColumn, null, null);
|
||||
}
|
||||
|
||||
public BeanPropertyOverride(String dbColumn, String sqlFormulaSelect, String sqlFormulaJoin) {
|
||||
this.dbColumn = InternString.intern(dbColumn);
|
||||
this.sqlFormulaSelect = InternString.intern(sqlFormulaSelect);
|
||||
this.sqlFormulaJoin = InternString.intern(sqlFormulaJoin);
|
||||
}
|
||||
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
public String getSqlFormulaSelect() {
|
||||
return sqlFormulaSelect;
|
||||
}
|
||||
|
||||
public String getSqlFormulaJoin() {
|
||||
return sqlFormulaJoin;
|
||||
}
|
||||
|
||||
public String replace(String src, String srcDbColumn){
|
||||
return StringHelper.replaceString(src, srcDbColumn, dbColumn);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
|
||||
/**
|
||||
* Used hold meta data when a bean property is overridden.
|
||||
* <p>
|
||||
* Typically this is for Embedded Beans.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPropertyOverride {
|
||||
|
||||
private final String dbColumn;
|
||||
|
||||
private final String sqlFormulaSelect;
|
||||
|
||||
private final String sqlFormulaJoin;
|
||||
|
||||
public BeanPropertyOverride(String dbColumn) {
|
||||
this(dbColumn, null, null);
|
||||
}
|
||||
|
||||
public BeanPropertyOverride(String dbColumn, String sqlFormulaSelect, String sqlFormulaJoin) {
|
||||
this.dbColumn = InternString.intern(dbColumn);
|
||||
this.sqlFormulaSelect = InternString.intern(sqlFormulaSelect);
|
||||
this.sqlFormulaJoin = InternString.intern(sqlFormulaJoin);
|
||||
}
|
||||
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
public String getSqlFormulaSelect() {
|
||||
return sqlFormulaSelect;
|
||||
}
|
||||
|
||||
public String getSqlFormulaJoin() {
|
||||
return sqlFormulaJoin;
|
||||
}
|
||||
|
||||
public String replace(String src, String srcDbColumn){
|
||||
return StringHelper.replaceString(src, srcDbColumn, dbColumn);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
|
||||
|
||||
public class BeanPropertySimpleCollection<T> extends BeanPropertyAssocMany<T> {
|
||||
|
||||
public BeanPropertySimpleCollection(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertySimpleCollection<T> deploy) {
|
||||
super(owner, descriptor, deploy);
|
||||
}
|
||||
|
||||
public void initialise() {
|
||||
super.initialise();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
|
||||
|
||||
public class BeanPropertySimpleCollection<T> extends BeanPropertyAssocMany<T> {
|
||||
|
||||
public BeanPropertySimpleCollection(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertySimpleCollection<T> deploy) {
|
||||
super(owner, descriptor, deploy);
|
||||
}
|
||||
|
||||
public void initialise() {
|
||||
super.initialise();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Default implementation for creating BeanControllers.
|
||||
*/
|
||||
public class BeanQueryAdapterManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanQueryAdapterManager.class);
|
||||
|
||||
private final List<BeanQueryAdapter> list;
|
||||
|
||||
public BeanQueryAdapterManager(BootupClasses bootupClasses){
|
||||
|
||||
list = bootupClasses.getBeanQueryAdapters();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController for a given entity type.
|
||||
*/
|
||||
public void addQueryAdapter(DeployBeanDescriptor<?> deployDesc){
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
BeanQueryAdapter c = list.get(i);
|
||||
if (c.isRegisterFor(deployDesc.getBeanType())){
|
||||
logger.debug("BeanQueryAdapter on[" + deployDesc.getFullName() + "] " + c.getClass().getName());
|
||||
deployDesc.addQueryAdapter(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Default implementation for creating BeanControllers.
|
||||
*/
|
||||
public class BeanQueryAdapterManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanQueryAdapterManager.class);
|
||||
|
||||
private final List<BeanQueryAdapter> list;
|
||||
|
||||
public BeanQueryAdapterManager(BootupClasses bootupClasses){
|
||||
|
||||
list = bootupClasses.getBeanQueryAdapters();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController for a given entity type.
|
||||
*/
|
||||
public void addQueryAdapter(DeployBeanDescriptor<?> deployDesc){
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
BeanQueryAdapter c = list.get(i);
|
||||
if (c.isRegisterFor(deployDesc.getBeanType())){
|
||||
logger.debug("BeanQueryAdapter on[" + deployDesc.getFullName() + "] " + c.getClass().getName());
|
||||
deployDesc.addQueryAdapter(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,149 +1,149 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.common.BeanSet;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
/**
|
||||
* Helper specifically for dealing with Sets.
|
||||
*/
|
||||
public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
/**
|
||||
* When attached to a specific many property.
|
||||
*/
|
||||
public BeanSetHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* For a query that returns a set.
|
||||
*/
|
||||
public BeanSetHelp() {
|
||||
this.many = null;
|
||||
this.targetDescriptor = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
if (bc instanceof BeanSet<?>) {
|
||||
BeanSet<?> beanSet = (BeanSet<?>) bc;
|
||||
if (beanSet.getActualSet() == null) {
|
||||
beanSet.setActualSet(new LinkedHashSet<Object>());
|
||||
}
|
||||
return beanSet;
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
collection.internalAdd(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmpty(EntityBean ownerBean) {
|
||||
BeanSet<T> beanSet = new BeanSet<T>(loader, ownerBean, propertyName);
|
||||
if (many != null) {
|
||||
beanSet.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanSet<T> beanSet = new BeanSet<T>(loader, parentBean, propertyName);
|
||||
beanSet.setModifyListening(many.getModifyListenMode());
|
||||
return beanSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
|
||||
BeanSet<?> newBeanSet = (BeanSet<?>) server.findSet(query, t);
|
||||
refresh(newBeanSet, parentBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanSet<?> newBeanSet = (BeanSet<?>) bc;
|
||||
|
||||
Set<?> current = (Set<?>) many.getValue(parentBean);
|
||||
|
||||
newBeanSet.setModifyListening(many.getModifyListenMode());
|
||||
if (current == null) {
|
||||
// the currentList is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanSet);
|
||||
|
||||
} else if (current instanceof BeanSet<?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanSet<?> currentBeanSet = (BeanSet<?>) current;
|
||||
currentBeanSet.setActualSet(newBeanSet.getActualSet());
|
||||
currentBeanSet.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
many.setValue(parentBean, newBeanSet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Set<?> set;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
BeanSet<?> bc = (BeanSet<?>) collection;
|
||||
if (!bc.isPopulated()) {
|
||||
if (explicitInclude) {
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
bc.size();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
set = bc.getActualSet();
|
||||
} else {
|
||||
set = (Set<?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) it.next());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.common.BeanSet;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
/**
|
||||
* Helper specifically for dealing with Sets.
|
||||
*/
|
||||
public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
/**
|
||||
* When attached to a specific many property.
|
||||
*/
|
||||
public BeanSetHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* For a query that returns a set.
|
||||
*/
|
||||
public BeanSetHelp() {
|
||||
this.many = null;
|
||||
this.targetDescriptor = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
if (bc instanceof BeanSet<?>) {
|
||||
BeanSet<?> beanSet = (BeanSet<?>) bc;
|
||||
if (beanSet.getActualSet() == null) {
|
||||
beanSet.setActualSet(new LinkedHashSet<Object>());
|
||||
}
|
||||
return beanSet;
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
collection.internalAdd(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmpty(EntityBean ownerBean) {
|
||||
BeanSet<T> beanSet = new BeanSet<T>(loader, ownerBean, propertyName);
|
||||
if (many != null) {
|
||||
beanSet.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanSet<T> beanSet = new BeanSet<T>(loader, parentBean, propertyName);
|
||||
beanSet.setModifyListening(many.getModifyListenMode());
|
||||
return beanSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
|
||||
BeanSet<?> newBeanSet = (BeanSet<?>) server.findSet(query, t);
|
||||
refresh(newBeanSet, parentBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanSet<?> newBeanSet = (BeanSet<?>) bc;
|
||||
|
||||
Set<?> current = (Set<?>) many.getValue(parentBean);
|
||||
|
||||
newBeanSet.setModifyListening(many.getModifyListenMode());
|
||||
if (current == null) {
|
||||
// the currentList is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanSet);
|
||||
|
||||
} else if (current instanceof BeanSet<?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanSet<?> currentBeanSet = (BeanSet<?>) current;
|
||||
currentBeanSet.setActualSet(newBeanSet.getActualSet());
|
||||
currentBeanSet.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
many.setValue(parentBean, newBeanSet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Set<?> set;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
BeanSet<?> bc = (BeanSet<?>) collection;
|
||||
if (!bc.isPopulated()) {
|
||||
if (explicitInclude) {
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
bc.size();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
set = bc.getActualSet();
|
||||
} else {
|
||||
set = (Set<?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) it.next());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +1,117 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
|
||||
* recursion issues due to the potentially bi-directional and circular
|
||||
* relationships between beans.
|
||||
* <p>
|
||||
* It holds the main deployment information and not all the detail that is held
|
||||
* in a BeanDescriptor.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanTable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanTable.class);
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
/**
|
||||
* The base table.
|
||||
*/
|
||||
private final String baseTable;
|
||||
|
||||
private final BeanProperty[] idProperties;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
*/
|
||||
public BeanTable(DeployBeanTable mutable, BeanDescriptorMap owner) {
|
||||
this.beanType = mutable.getBeanType();
|
||||
this.baseTable = InternString.intern(mutable.getBaseTable());
|
||||
this.idProperties = mutable.createIdProperties(owner);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table for this BeanTable.
|
||||
* This is used to determine the join information
|
||||
* for associations.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unqualified base table.
|
||||
*
|
||||
* @return the unqualified base table
|
||||
*/
|
||||
public String getUnqualifiedBaseTable(){
|
||||
final String[] chunks = baseTable.split("\\.");
|
||||
return chunks.length == 2 ? chunks[1] :chunks[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id properties.
|
||||
*/
|
||||
public BeanProperty[] getIdProperties() {
|
||||
return idProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class for this beanTable.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse) {
|
||||
|
||||
boolean complexKey = false;
|
||||
BeanProperty[] props = idProperties;
|
||||
|
||||
if (idProperties.length == 1){
|
||||
if (idProperties[0] instanceof BeanPropertyAssocOne<?>) {
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>)idProperties[0];
|
||||
props = assocOne.getProperties();
|
||||
complexKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
|
||||
String lc = props[i].getDbColumn();
|
||||
String fk = lc;
|
||||
if (foreignKeyPrefix != null){
|
||||
fk = foreignKeyPrefix+"_"+fk;
|
||||
}
|
||||
|
||||
if (complexKey){
|
||||
// just to copy the column name rather than prefix with the foreignKeyPrefix.
|
||||
// I think that with complex keys this is the more common approach.
|
||||
String msg = "On table["+baseTable+"] foreign key column ["+lc+"]";
|
||||
logger.debug(msg);
|
||||
fk = lc;
|
||||
}
|
||||
|
||||
DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk);
|
||||
if (reverse){
|
||||
joinCol = joinCol.reverse();
|
||||
}
|
||||
join.addJoinColumn(joinCol);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
|
||||
* recursion issues due to the potentially bi-directional and circular
|
||||
* relationships between beans.
|
||||
* <p>
|
||||
* It holds the main deployment information and not all the detail that is held
|
||||
* in a BeanDescriptor.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanTable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanTable.class);
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
/**
|
||||
* The base table.
|
||||
*/
|
||||
private final String baseTable;
|
||||
|
||||
private final BeanProperty[] idProperties;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
*/
|
||||
public BeanTable(DeployBeanTable mutable, BeanDescriptorMap owner) {
|
||||
this.beanType = mutable.getBeanType();
|
||||
this.baseTable = InternString.intern(mutable.getBaseTable());
|
||||
this.idProperties = mutable.createIdProperties(owner);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table for this BeanTable.
|
||||
* This is used to determine the join information
|
||||
* for associations.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unqualified base table.
|
||||
*
|
||||
* @return the unqualified base table
|
||||
*/
|
||||
public String getUnqualifiedBaseTable(){
|
||||
final String[] chunks = baseTable.split("\\.");
|
||||
return chunks.length == 2 ? chunks[1] :chunks[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id properties.
|
||||
*/
|
||||
public BeanProperty[] getIdProperties() {
|
||||
return idProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class for this beanTable.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse) {
|
||||
|
||||
boolean complexKey = false;
|
||||
BeanProperty[] props = idProperties;
|
||||
|
||||
if (idProperties.length == 1){
|
||||
if (idProperties[0] instanceof BeanPropertyAssocOne<?>) {
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>)idProperties[0];
|
||||
props = assocOne.getProperties();
|
||||
complexKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
|
||||
String lc = props[i].getDbColumn();
|
||||
String fk = lc;
|
||||
if (foreignKeyPrefix != null){
|
||||
fk = foreignKeyPrefix+"_"+fk;
|
||||
}
|
||||
|
||||
if (complexKey){
|
||||
// just to copy the column name rather than prefix with the foreignKeyPrefix.
|
||||
// I think that with complex keys this is the more common approach.
|
||||
String msg = "On table["+baseTable+"] foreign key column ["+lc+"]";
|
||||
logger.debug(msg);
|
||||
fk = lc;
|
||||
}
|
||||
|
||||
DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk);
|
||||
if (reverse){
|
||||
joinCol = joinCol.reverse();
|
||||
}
|
||||
join.addJoinColumn(joinCol);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
/**
|
||||
* Holds multiple column unique constraints defined for an entity.
|
||||
*/
|
||||
public class CompoundUniqueContraint {
|
||||
|
||||
private final String[] columns;
|
||||
|
||||
public CompoundUniqueContraint(String[] columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the columns that make up this unique constraint.
|
||||
*/
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
/**
|
||||
* Holds multiple column unique constraints defined for an entity.
|
||||
*/
|
||||
public class CompoundUniqueContraint {
|
||||
|
||||
private final String[] columns;
|
||||
|
||||
public CompoundUniqueContraint(String[] columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the columns that make up this unique constraint.
|
||||
*/
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
/**
|
||||
* Provides context when performing a bean copy.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class CopyContext {
|
||||
|
||||
private final boolean vanillaMode;
|
||||
|
||||
private final boolean sharing;
|
||||
|
||||
private final PersistenceContext pc;
|
||||
|
||||
public CopyContext(boolean vanillaMode, boolean sharing) {
|
||||
this.vanillaMode = vanillaMode;
|
||||
this.sharing = sharing;
|
||||
this.pc = new DefaultPersistenceContext();
|
||||
}
|
||||
|
||||
public CopyContext(boolean vanillaMode) {
|
||||
this(vanillaMode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the copy should be a vanilla bean.
|
||||
*/
|
||||
public boolean isVanillaMode() {
|
||||
return vanillaMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the copy should be safe for sharing.
|
||||
*/
|
||||
public boolean isSharing() {
|
||||
return sharing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persistence context used during the copy.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return pc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the bean if absent into the persistence context.
|
||||
*/
|
||||
public Object putIfAbsent(Object id, Object bean){
|
||||
return pc.putIfAbsent(id, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean for the given type and id from the persistence context.
|
||||
*/
|
||||
public Object get(Class<?> beanType, Object beanId){
|
||||
return pc.get(beanType, beanId);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
/**
|
||||
* Provides context when performing a bean copy.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class CopyContext {
|
||||
|
||||
private final boolean vanillaMode;
|
||||
|
||||
private final boolean sharing;
|
||||
|
||||
private final PersistenceContext pc;
|
||||
|
||||
public CopyContext(boolean vanillaMode, boolean sharing) {
|
||||
this.vanillaMode = vanillaMode;
|
||||
this.sharing = sharing;
|
||||
this.pc = new DefaultPersistenceContext();
|
||||
}
|
||||
|
||||
public CopyContext(boolean vanillaMode) {
|
||||
this(vanillaMode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the copy should be a vanilla bean.
|
||||
*/
|
||||
public boolean isVanillaMode() {
|
||||
return vanillaMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the copy should be safe for sharing.
|
||||
*/
|
||||
public boolean isSharing() {
|
||||
return sharing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persistence context used during the copy.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return pc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the bean if absent into the persistence context.
|
||||
*/
|
||||
public Object putIfAbsent(Object id, Object bean){
|
||||
return pc.putIfAbsent(id, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean for the given type and id from the persistence context.
|
||||
*/
|
||||
public Object get(Class<?> beanType, Object beanId){
|
||||
return pc.get(beanType, beanId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
public class DRawSqlColumnInfo {
|
||||
|
||||
final String name;
|
||||
|
||||
final String label;
|
||||
|
||||
final String propertyName;
|
||||
|
||||
final boolean scalarProperty;
|
||||
|
||||
public DRawSqlColumnInfo(String name, String label, String propertyName, boolean scalarProperty) {
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.propertyName = propertyName;
|
||||
this.scalarProperty = scalarProperty;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public boolean isScalarProperty() {
|
||||
return scalarProperty;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "name:" + name + " label:" + label + " prop:" + propertyName;
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
public class DRawSqlColumnInfo {
|
||||
|
||||
final String name;
|
||||
|
||||
final String label;
|
||||
|
||||
final String propertyName;
|
||||
|
||||
final boolean scalarProperty;
|
||||
|
||||
public DRawSqlColumnInfo(String name, String label, String propertyName, boolean scalarProperty) {
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.propertyName = propertyName;
|
||||
this.scalarProperty = scalarProperty;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public boolean isScalarProperty() {
|
||||
return scalarProperty;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "name:" + name + " label:" + label + " prop:" + propertyName;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,61 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
|
||||
/**
|
||||
* Default implementation for BeanFinderFactory.
|
||||
*/
|
||||
public class DefaultBeanFinderManager implements BeanFinderManager {
|
||||
|
||||
HashMap<Class<?>, BeanFinder<?>> registerFor = new HashMap<Class<?>, BeanFinder<?>>();
|
||||
|
||||
public int createBeanFinders(List<Class<?>> finderClassList) {
|
||||
|
||||
for (Class<?> cls : finderClassList) {
|
||||
Class<?> entityType = getEntityClass(cls);
|
||||
try {
|
||||
BeanFinder<?> beanFinder = (BeanFinder<?>) cls.newInstance();
|
||||
registerFor.put(entityType, beanFinder);
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return registerFor.size();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return registerFor.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanFinder for a given entity type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType) {
|
||||
return (BeanFinder<T>)registerFor.get(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the entity class given the controller class.
|
||||
* <p>
|
||||
* This uses reflection to find the generics parameter type.
|
||||
* </p>
|
||||
*/
|
||||
private Class<?> getEntityClass(Class<?> controller){
|
||||
|
||||
Class<?> cls = ParamTypeUtil.findParamType(controller, BeanFinder.class);
|
||||
|
||||
if (cls == null){
|
||||
String msg = "Could not determine the entity class (generics parameter type) from "+controller+" using reflection.";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
|
||||
/**
|
||||
* Default implementation for BeanFinderFactory.
|
||||
*/
|
||||
public class DefaultBeanFinderManager implements BeanFinderManager {
|
||||
|
||||
HashMap<Class<?>, BeanFinder<?>> registerFor = new HashMap<Class<?>, BeanFinder<?>>();
|
||||
|
||||
public int createBeanFinders(List<Class<?>> finderClassList) {
|
||||
|
||||
for (Class<?> cls : finderClassList) {
|
||||
Class<?> entityType = getEntityClass(cls);
|
||||
try {
|
||||
BeanFinder<?> beanFinder = (BeanFinder<?>) cls.newInstance();
|
||||
registerFor.put(entityType, beanFinder);
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return registerFor.size();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return registerFor.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanFinder for a given entity type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType) {
|
||||
return (BeanFinder<T>)registerFor.get(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the entity class given the controller class.
|
||||
* <p>
|
||||
* This uses reflection to find the generics parameter type.
|
||||
* </p>
|
||||
*/
|
||||
private Class<?> getEntityClass(Class<?> controller){
|
||||
|
||||
Class<?> cls = ParamTypeUtil.findParamType(controller, BeanFinder.class);
|
||||
|
||||
if (cls == null){
|
||||
String msg = "Could not determine the entity class (generics parameter type) from "+controller+" using reflection.";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,171 +1,171 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.resource.ResourceContent;
|
||||
import com.avaje.ebeaninternal.server.lib.resource.ResourceSource;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
import com.avaje.ebeaninternal.server.lib.util.DnodeReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Controls the creation and caching of BeanManager's, BeanDescriptors,
|
||||
* BeanTable etc for both beans and tables(MapBeans).
|
||||
* <p>
|
||||
* Also supports some other deployment features such as type conversion.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployOrmXml {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployOrmXml.class);
|
||||
|
||||
private final HashMap<String, DNativeQuery> nativeQueryCache;
|
||||
|
||||
private final ArrayList<Dnode> ormXmlList;
|
||||
|
||||
private final ResourceSource resSource;
|
||||
|
||||
public DeployOrmXml(ResourceSource resSource) {
|
||||
|
||||
this.resSource = resSource;
|
||||
this.nativeQueryCache = new HashMap<String, DNativeQuery>();
|
||||
this.ormXmlList = findAllOrmXml();
|
||||
|
||||
|
||||
initialiseNativeQueries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the native queries in ALL orm xml deployment.
|
||||
*/
|
||||
private void initialiseNativeQueries() {
|
||||
for (Dnode ormXml : ormXmlList) {
|
||||
initialiseNativeQueries(ormXml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the native queries in this particular orm xml deployment.
|
||||
*/
|
||||
private void initialiseNativeQueries(Dnode ormXml) {
|
||||
|
||||
Dnode entityMappings = ormXml.find("entity-mappings");
|
||||
if (entityMappings != null) {
|
||||
List<Dnode> nq = entityMappings.findAll("named-native-query", 1);
|
||||
for (int i = 0; i < nq.size(); i++) {
|
||||
Dnode nqNode = nq.get(i);
|
||||
Dnode nqQueryNode = nqNode.find("query");
|
||||
if (nqQueryNode != null) {
|
||||
String queryContent = nqQueryNode.getNodeContent();
|
||||
String queryName = (String) nqNode.getAttribute("name");
|
||||
|
||||
if (queryName != null && queryContent != null) {
|
||||
DNativeQuery query = new DNativeQuery(queryContent);
|
||||
nativeQueryCache.put(queryName, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a native named query.
|
||||
* <p>
|
||||
* These are loaded from the orm.xml deployment file.
|
||||
* </p>
|
||||
*/
|
||||
public DNativeQuery getNativeQuery(String name) {
|
||||
return nativeQueryCache.get(name);
|
||||
}
|
||||
|
||||
private ArrayList<Dnode> findAllOrmXml() {
|
||||
|
||||
ArrayList<Dnode> ormXmlList = new ArrayList<Dnode>();
|
||||
|
||||
|
||||
String defaultFile = "orm.xml";
|
||||
readOrmXml(defaultFile, ormXmlList);
|
||||
|
||||
if (!ormXmlList.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Dnode ox : ormXmlList) {
|
||||
sb.append(", ").append(ox.getAttribute("ebean.filename"));
|
||||
}
|
||||
String loadedFiles = sb.toString().substring(2);
|
||||
logger.info("Deployment xml [" + loadedFiles + "] loaded.");
|
||||
}
|
||||
|
||||
return ormXmlList;
|
||||
}
|
||||
|
||||
private boolean readOrmXml(String ormXmlName, ArrayList<Dnode> ormXmlList) {
|
||||
|
||||
try {
|
||||
Dnode ormXml = null;
|
||||
ResourceContent content = resSource.getContent(ormXmlName);
|
||||
if (content != null) {
|
||||
// servlet resource or file system...
|
||||
ormXml = readOrmXml(content.getInputStream());
|
||||
|
||||
} else {
|
||||
// try the classpath...
|
||||
ormXml = readOrmXmlFromClasspath(ormXmlName);
|
||||
}
|
||||
|
||||
if (ormXml != null) {
|
||||
ormXml.setAttribute("ebean.filename", ormXmlName);
|
||||
ormXmlList.add(ormXml);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("error reading orm xml deployment " + ormXmlName, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Dnode readOrmXmlFromClasspath(String ormXmlName) throws IOException {
|
||||
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(ormXmlName);
|
||||
if (is == null) {
|
||||
return null;
|
||||
} else {
|
||||
return readOrmXml(is);
|
||||
}
|
||||
}
|
||||
|
||||
private Dnode readOrmXml(InputStream in) throws IOException {
|
||||
DnodeReader reader = new DnodeReader();
|
||||
Dnode ormXml = reader.parseXml(in);
|
||||
in.close();
|
||||
return ormXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the deployment xml for a given entity. This will return null if no
|
||||
* matching deployment xml is found for this entity.
|
||||
* <p>
|
||||
* This searches all the ormXml files and returns the first match.
|
||||
* </p>
|
||||
*/
|
||||
public Dnode findEntityDeploymentXml(String className) {
|
||||
|
||||
for (Dnode ormXml : ormXmlList) {
|
||||
Dnode entityMappings = ormXml.find("entity-mappings");
|
||||
|
||||
List<Dnode> entities = entityMappings.findAll("entity", "class", className, 1);
|
||||
if (entities.size() == 1) {
|
||||
return entities.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.resource.ResourceContent;
|
||||
import com.avaje.ebeaninternal.server.lib.resource.ResourceSource;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
import com.avaje.ebeaninternal.server.lib.util.DnodeReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Controls the creation and caching of BeanManager's, BeanDescriptors,
|
||||
* BeanTable etc for both beans and tables(MapBeans).
|
||||
* <p>
|
||||
* Also supports some other deployment features such as type conversion.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployOrmXml {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployOrmXml.class);
|
||||
|
||||
private final HashMap<String, DNativeQuery> nativeQueryCache;
|
||||
|
||||
private final ArrayList<Dnode> ormXmlList;
|
||||
|
||||
private final ResourceSource resSource;
|
||||
|
||||
public DeployOrmXml(ResourceSource resSource) {
|
||||
|
||||
this.resSource = resSource;
|
||||
this.nativeQueryCache = new HashMap<String, DNativeQuery>();
|
||||
this.ormXmlList = findAllOrmXml();
|
||||
|
||||
|
||||
initialiseNativeQueries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the native queries in ALL orm xml deployment.
|
||||
*/
|
||||
private void initialiseNativeQueries() {
|
||||
for (Dnode ormXml : ormXmlList) {
|
||||
initialiseNativeQueries(ormXml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the native queries in this particular orm xml deployment.
|
||||
*/
|
||||
private void initialiseNativeQueries(Dnode ormXml) {
|
||||
|
||||
Dnode entityMappings = ormXml.find("entity-mappings");
|
||||
if (entityMappings != null) {
|
||||
List<Dnode> nq = entityMappings.findAll("named-native-query", 1);
|
||||
for (int i = 0; i < nq.size(); i++) {
|
||||
Dnode nqNode = nq.get(i);
|
||||
Dnode nqQueryNode = nqNode.find("query");
|
||||
if (nqQueryNode != null) {
|
||||
String queryContent = nqQueryNode.getNodeContent();
|
||||
String queryName = (String) nqNode.getAttribute("name");
|
||||
|
||||
if (queryName != null && queryContent != null) {
|
||||
DNativeQuery query = new DNativeQuery(queryContent);
|
||||
nativeQueryCache.put(queryName, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a native named query.
|
||||
* <p>
|
||||
* These are loaded from the orm.xml deployment file.
|
||||
* </p>
|
||||
*/
|
||||
public DNativeQuery getNativeQuery(String name) {
|
||||
return nativeQueryCache.get(name);
|
||||
}
|
||||
|
||||
private ArrayList<Dnode> findAllOrmXml() {
|
||||
|
||||
ArrayList<Dnode> ormXmlList = new ArrayList<Dnode>();
|
||||
|
||||
|
||||
String defaultFile = "orm.xml";
|
||||
readOrmXml(defaultFile, ormXmlList);
|
||||
|
||||
if (!ormXmlList.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Dnode ox : ormXmlList) {
|
||||
sb.append(", ").append(ox.getAttribute("ebean.filename"));
|
||||
}
|
||||
String loadedFiles = sb.toString().substring(2);
|
||||
logger.info("Deployment xml [" + loadedFiles + "] loaded.");
|
||||
}
|
||||
|
||||
return ormXmlList;
|
||||
}
|
||||
|
||||
private boolean readOrmXml(String ormXmlName, ArrayList<Dnode> ormXmlList) {
|
||||
|
||||
try {
|
||||
Dnode ormXml = null;
|
||||
ResourceContent content = resSource.getContent(ormXmlName);
|
||||
if (content != null) {
|
||||
// servlet resource or file system...
|
||||
ormXml = readOrmXml(content.getInputStream());
|
||||
|
||||
} else {
|
||||
// try the classpath...
|
||||
ormXml = readOrmXmlFromClasspath(ormXmlName);
|
||||
}
|
||||
|
||||
if (ormXml != null) {
|
||||
ormXml.setAttribute("ebean.filename", ormXmlName);
|
||||
ormXmlList.add(ormXml);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("error reading orm xml deployment " + ormXmlName, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Dnode readOrmXmlFromClasspath(String ormXmlName) throws IOException {
|
||||
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(ormXmlName);
|
||||
if (is == null) {
|
||||
return null;
|
||||
} else {
|
||||
return readOrmXml(is);
|
||||
}
|
||||
}
|
||||
|
||||
private Dnode readOrmXml(InputStream in) throws IOException {
|
||||
DnodeReader reader = new DnodeReader();
|
||||
Dnode ormXml = reader.parseXml(in);
|
||||
in.close();
|
||||
return ormXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the deployment xml for a given entity. This will return null if no
|
||||
* matching deployment xml is found for this entity.
|
||||
* <p>
|
||||
* This searches all the ormXml files and returns the first match.
|
||||
* </p>
|
||||
*/
|
||||
public Dnode findEntityDeploymentXml(String className) {
|
||||
|
||||
for (Dnode ormXml : ormXmlList) {
|
||||
Dnode entityMappings = ormXml.find("entity-mappings");
|
||||
|
||||
List<Dnode> entities = entityMappings.findAll("entity", "class", className, 1);
|
||||
if (entities.size() == 1) {
|
||||
return entities.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Determine the Many Type for a property.
|
||||
*/
|
||||
public class DetermineManyType {
|
||||
|
||||
public DetermineManyType() {
|
||||
}
|
||||
|
||||
public ManyType getManyType(Class<?> type) {
|
||||
if (type.equals(List.class)) {
|
||||
return ManyType.JAVA_LIST;
|
||||
}
|
||||
if (type.equals(Set.class)) {
|
||||
return ManyType.JAVA_SET;
|
||||
}
|
||||
if (type.equals(Map.class)) {
|
||||
return ManyType.JAVA_MAP;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Determine the Many Type for a property.
|
||||
*/
|
||||
public class DetermineManyType {
|
||||
|
||||
public DetermineManyType() {
|
||||
}
|
||||
|
||||
public ManyType getManyType(Class<?> type) {
|
||||
if (type.equals(List.class)) {
|
||||
return ManyType.JAVA_LIST;
|
||||
}
|
||||
if (type.equals(Set.class)) {
|
||||
return ManyType.JAVA_SET;
|
||||
}
|
||||
if (type.equals(Map.class)) {
|
||||
return ManyType.JAVA_MAP;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
|
||||
/**
|
||||
* The Exported foreign key and property.
|
||||
* <p>
|
||||
* Used to for Assoc Manys to create references etc.
|
||||
* </p>
|
||||
*/
|
||||
public class ExportedProperty {
|
||||
|
||||
private final String foreignDbColumn;
|
||||
|
||||
private final BeanProperty property;
|
||||
|
||||
private final boolean embedded;
|
||||
|
||||
public ExportedProperty(boolean embedded, String foreignDbColumn, BeanProperty property) {
|
||||
this.embedded = embedded;
|
||||
this.foreignDbColumn = InternString.intern(foreignDbColumn);
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is part of an embedded concatinated key.
|
||||
*/
|
||||
public boolean isEmbedded() {
|
||||
return embedded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value from the bean.
|
||||
*/
|
||||
public Object getValue(EntityBean bean){
|
||||
return property.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column matching this property.
|
||||
* <p>
|
||||
* We use this foreign database column in the query predicates
|
||||
* in preference to a parentProperty.idProperty = value.
|
||||
* Just using the foreign database column avoids triggering
|
||||
* a join to the 'parent' table.
|
||||
* </p>
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
|
||||
/**
|
||||
* The Exported foreign key and property.
|
||||
* <p>
|
||||
* Used to for Assoc Manys to create references etc.
|
||||
* </p>
|
||||
*/
|
||||
public class ExportedProperty {
|
||||
|
||||
private final String foreignDbColumn;
|
||||
|
||||
private final BeanProperty property;
|
||||
|
||||
private final boolean embedded;
|
||||
|
||||
public ExportedProperty(boolean embedded, String foreignDbColumn, BeanProperty property) {
|
||||
this.embedded = embedded;
|
||||
this.foreignDbColumn = InternString.intern(foreignDbColumn);
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is part of an embedded concatinated key.
|
||||
*/
|
||||
public boolean isEmbedded() {
|
||||
return embedded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value from the bean.
|
||||
*/
|
||||
public Object getValue(EntityBean bean){
|
||||
return property.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column matching this property.
|
||||
* <p>
|
||||
* We use this foreign database column in the query predicates
|
||||
* in preference to a parentProperty.idProperty = value.
|
||||
* Just using the foreign database column avoids triggering
|
||||
* a join to the 'parent' table.
|
||||
* </p>
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,344 +1,344 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInheritInfo;
|
||||
import com.avaje.ebeaninternal.server.query.SqlTreeProperties;
|
||||
|
||||
/**
|
||||
* Represents a node in the Inheritance tree. Holds information regarding Super Subclass support.
|
||||
*/
|
||||
public class InheritInfo {
|
||||
|
||||
private final String discriminatorStringValue;
|
||||
private final Object discriminatorValue;
|
||||
|
||||
private final String discriminatorColumn;
|
||||
|
||||
private final int discriminatorType;
|
||||
|
||||
private final int discriminatorLength;
|
||||
|
||||
private final String where;
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final ArrayList<InheritInfo> children = new ArrayList<InheritInfo>();
|
||||
|
||||
/**
|
||||
* Map of discriminator values to InheritInfo.
|
||||
*/
|
||||
private final HashMap<String, InheritInfo> discMap;
|
||||
|
||||
/**
|
||||
* Map of class types to InheritInfo (taking into account subclass proxy classes).
|
||||
*/
|
||||
private final HashMap<String, InheritInfo> typeMap;
|
||||
|
||||
private final InheritInfo parent;
|
||||
|
||||
private final InheritInfo root;
|
||||
|
||||
private BeanDescriptor<?> descriptor;
|
||||
|
||||
public InheritInfo(InheritInfo r, InheritInfo parent, DeployInheritInfo deploy) {
|
||||
|
||||
this.parent = parent;
|
||||
this.type = deploy.getType();
|
||||
this.discriminatorColumn = InternString.intern(deploy.getDiscriminatorColumn(parent));
|
||||
this.discriminatorValue = deploy.getDiscriminatorObjectValue();
|
||||
this.discriminatorStringValue = deploy.getDiscriminatorStringValue();
|
||||
|
||||
this.discriminatorType = deploy.getDiscriminatorType(parent);
|
||||
this.discriminatorLength = deploy.getDiscriminatorLength(parent);
|
||||
this.where = InternString.intern(deploy.getWhere());
|
||||
|
||||
if (r == null) {
|
||||
// this is a root node
|
||||
root = this;
|
||||
discMap = new HashMap<String, InheritInfo>();
|
||||
typeMap = new HashMap<String, InheritInfo>();
|
||||
registerWithRoot(this);
|
||||
|
||||
} else {
|
||||
this.root = r;
|
||||
// register with the root node...
|
||||
discMap = null;
|
||||
typeMap = null;
|
||||
root.registerWithRoot(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit all the children in the inheritance tree.
|
||||
*/
|
||||
public void visitChildren(InheritInfoVisitor visitor) {
|
||||
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
InheritInfo child = children.get(i);
|
||||
visitor.visit(child);
|
||||
child.visitChildren(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if anything in the inheritance hierarchy has a relationship with a save cascade on
|
||||
* it.
|
||||
*/
|
||||
public boolean isSaveRecurseSkippable() {
|
||||
return root.isNodeSaveRecurseSkippable();
|
||||
}
|
||||
|
||||
private boolean isNodeSaveRecurseSkippable() {
|
||||
if (!descriptor.isSaveRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
InheritInfo child = children.get(i);
|
||||
if (!child.isNodeSaveRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if anything in the inheritance hierarchy has a relationship with a delete cascade
|
||||
* on it.
|
||||
*/
|
||||
public boolean isDeleteRecurseSkippable() {
|
||||
return root.isNodeDeleteRecurseSkippable();
|
||||
}
|
||||
|
||||
private boolean isNodeDeleteRecurseSkippable() {
|
||||
if (!descriptor.isDeleteRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
InheritInfo child = children.get(i);
|
||||
if (!child.isNodeDeleteRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the descriptor for this node.
|
||||
*/
|
||||
public void setDescriptor(BeanDescriptor<?> descriptor) {
|
||||
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated BeanDescriptor for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bean property additionally looking in the sub types.
|
||||
*/
|
||||
public BeanProperty findSubTypeProperty(String propertyName) {
|
||||
|
||||
BeanProperty prop = null;
|
||||
|
||||
for (int i = 0, x = children.size(); i < x; i++) {
|
||||
InheritInfo childInfo = children.get(i);
|
||||
|
||||
// recursively search this child bean descriptor
|
||||
prop = childInfo.getBeanDescriptor().findBeanProperty(propertyName);
|
||||
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the local properties for each sub class below this one.
|
||||
*/
|
||||
public void addChildrenProperties(SqlTreeProperties selectProps) {
|
||||
|
||||
for (int i = 0, x = children.size(); i < x; i++) {
|
||||
InheritInfo childInfo = children.get(i);
|
||||
selectProps.add(childInfo.descriptor.propertiesLocal());
|
||||
|
||||
childInfo.addChildrenProperties(selectProps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated InheritInfo for this DB row read.
|
||||
*/
|
||||
public InheritInfo readType(DbReadContext ctx) throws SQLException {
|
||||
|
||||
String discValue = ctx.getDataReader().getString();
|
||||
return readType(discValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated InheritInfo for this discriminator value.
|
||||
*/
|
||||
public InheritInfo readType(String discValue) {
|
||||
|
||||
if (discValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InheritInfo typeInfo = root.getType(discValue);
|
||||
if (typeInfo == null) {
|
||||
throw new PersistenceException("Inheritance type for discriminator value [" + discValue + "] was not found?");
|
||||
}
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated InheritInfo for this bean type.
|
||||
*/
|
||||
public InheritInfo readType(Class<?> beanType) {
|
||||
|
||||
InheritInfo typeInfo = root.getTypeByClass(beanType);
|
||||
if (typeInfo == null) {
|
||||
throw new PersistenceException("Inheritance type for bean type [" + beanType.getName() + "] was not found?");
|
||||
}
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an EntityBean for this type.
|
||||
*/
|
||||
public EntityBean createEntityBean() {
|
||||
return descriptor.createEntityBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IdBinder for this type.
|
||||
*/
|
||||
public IdBinder getIdBinder() {
|
||||
return descriptor.getIdBinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the type.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the root node of the tree.
|
||||
* <p>
|
||||
* The root has a map of discriminator values to types.
|
||||
* </p>
|
||||
*/
|
||||
public InheritInfo getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent node.
|
||||
*/
|
||||
public InheritInfo getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is abstract node.
|
||||
*/
|
||||
public boolean isAbstract() {
|
||||
return (discriminatorValue == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the root node.
|
||||
*/
|
||||
public boolean isRoot() {
|
||||
return parent == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a discriminator get the inheritance information for this tree.
|
||||
*/
|
||||
public InheritInfo getType(String discValue) {
|
||||
return discMap.get(discValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the InheritInfo for the given bean type.
|
||||
*/
|
||||
private InheritInfo getTypeByClass(Class<?> beanType) {
|
||||
return typeMap.get(beanType.getName());
|
||||
}
|
||||
|
||||
private void registerWithRoot(InheritInfo info) {
|
||||
if (info.getDiscriminatorStringValue() != null) {
|
||||
String stringDiscValue = info.getDiscriminatorStringValue();
|
||||
discMap.put(stringDiscValue, info);
|
||||
}
|
||||
typeMap.put(info.getType().getName(), info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child node.
|
||||
*/
|
||||
public void addChild(InheritInfo childInfo) {
|
||||
children.add(childInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the derived where for the discriminator.
|
||||
*/
|
||||
public String getWhere() {
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column name of the discriminator.
|
||||
*/
|
||||
public String getDiscriminatorColumn() {
|
||||
return discriminatorColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sql type of the discriminator value.
|
||||
*/
|
||||
public int getDiscriminatorType() {
|
||||
return discriminatorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the discriminator column.
|
||||
*/
|
||||
public int getDiscriminatorLength() {
|
||||
return discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the discriminator value for this node.
|
||||
*/
|
||||
public String getDiscriminatorStringValue() {
|
||||
return discriminatorStringValue;
|
||||
}
|
||||
|
||||
public Object getDiscriminatorValue() {
|
||||
return discriminatorValue;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "InheritInfo[" + type.getName() + "] disc[" + discriminatorStringValue + "]";
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInheritInfo;
|
||||
import com.avaje.ebeaninternal.server.query.SqlTreeProperties;
|
||||
|
||||
/**
|
||||
* Represents a node in the Inheritance tree. Holds information regarding Super Subclass support.
|
||||
*/
|
||||
public class InheritInfo {
|
||||
|
||||
private final String discriminatorStringValue;
|
||||
private final Object discriminatorValue;
|
||||
|
||||
private final String discriminatorColumn;
|
||||
|
||||
private final int discriminatorType;
|
||||
|
||||
private final int discriminatorLength;
|
||||
|
||||
private final String where;
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final ArrayList<InheritInfo> children = new ArrayList<InheritInfo>();
|
||||
|
||||
/**
|
||||
* Map of discriminator values to InheritInfo.
|
||||
*/
|
||||
private final HashMap<String, InheritInfo> discMap;
|
||||
|
||||
/**
|
||||
* Map of class types to InheritInfo (taking into account subclass proxy classes).
|
||||
*/
|
||||
private final HashMap<String, InheritInfo> typeMap;
|
||||
|
||||
private final InheritInfo parent;
|
||||
|
||||
private final InheritInfo root;
|
||||
|
||||
private BeanDescriptor<?> descriptor;
|
||||
|
||||
public InheritInfo(InheritInfo r, InheritInfo parent, DeployInheritInfo deploy) {
|
||||
|
||||
this.parent = parent;
|
||||
this.type = deploy.getType();
|
||||
this.discriminatorColumn = InternString.intern(deploy.getDiscriminatorColumn(parent));
|
||||
this.discriminatorValue = deploy.getDiscriminatorObjectValue();
|
||||
this.discriminatorStringValue = deploy.getDiscriminatorStringValue();
|
||||
|
||||
this.discriminatorType = deploy.getDiscriminatorType(parent);
|
||||
this.discriminatorLength = deploy.getDiscriminatorLength(parent);
|
||||
this.where = InternString.intern(deploy.getWhere());
|
||||
|
||||
if (r == null) {
|
||||
// this is a root node
|
||||
root = this;
|
||||
discMap = new HashMap<String, InheritInfo>();
|
||||
typeMap = new HashMap<String, InheritInfo>();
|
||||
registerWithRoot(this);
|
||||
|
||||
} else {
|
||||
this.root = r;
|
||||
// register with the root node...
|
||||
discMap = null;
|
||||
typeMap = null;
|
||||
root.registerWithRoot(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit all the children in the inheritance tree.
|
||||
*/
|
||||
public void visitChildren(InheritInfoVisitor visitor) {
|
||||
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
InheritInfo child = children.get(i);
|
||||
visitor.visit(child);
|
||||
child.visitChildren(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if anything in the inheritance hierarchy has a relationship with a save cascade on
|
||||
* it.
|
||||
*/
|
||||
public boolean isSaveRecurseSkippable() {
|
||||
return root.isNodeSaveRecurseSkippable();
|
||||
}
|
||||
|
||||
private boolean isNodeSaveRecurseSkippable() {
|
||||
if (!descriptor.isSaveRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
InheritInfo child = children.get(i);
|
||||
if (!child.isNodeSaveRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if anything in the inheritance hierarchy has a relationship with a delete cascade
|
||||
* on it.
|
||||
*/
|
||||
public boolean isDeleteRecurseSkippable() {
|
||||
return root.isNodeDeleteRecurseSkippable();
|
||||
}
|
||||
|
||||
private boolean isNodeDeleteRecurseSkippable() {
|
||||
if (!descriptor.isDeleteRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
InheritInfo child = children.get(i);
|
||||
if (!child.isNodeDeleteRecurseSkippable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the descriptor for this node.
|
||||
*/
|
||||
public void setDescriptor(BeanDescriptor<?> descriptor) {
|
||||
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated BeanDescriptor for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bean property additionally looking in the sub types.
|
||||
*/
|
||||
public BeanProperty findSubTypeProperty(String propertyName) {
|
||||
|
||||
BeanProperty prop = null;
|
||||
|
||||
for (int i = 0, x = children.size(); i < x; i++) {
|
||||
InheritInfo childInfo = children.get(i);
|
||||
|
||||
// recursively search this child bean descriptor
|
||||
prop = childInfo.getBeanDescriptor().findBeanProperty(propertyName);
|
||||
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the local properties for each sub class below this one.
|
||||
*/
|
||||
public void addChildrenProperties(SqlTreeProperties selectProps) {
|
||||
|
||||
for (int i = 0, x = children.size(); i < x; i++) {
|
||||
InheritInfo childInfo = children.get(i);
|
||||
selectProps.add(childInfo.descriptor.propertiesLocal());
|
||||
|
||||
childInfo.addChildrenProperties(selectProps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated InheritInfo for this DB row read.
|
||||
*/
|
||||
public InheritInfo readType(DbReadContext ctx) throws SQLException {
|
||||
|
||||
String discValue = ctx.getDataReader().getString();
|
||||
return readType(discValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated InheritInfo for this discriminator value.
|
||||
*/
|
||||
public InheritInfo readType(String discValue) {
|
||||
|
||||
if (discValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InheritInfo typeInfo = root.getType(discValue);
|
||||
if (typeInfo == null) {
|
||||
throw new PersistenceException("Inheritance type for discriminator value [" + discValue + "] was not found?");
|
||||
}
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated InheritInfo for this bean type.
|
||||
*/
|
||||
public InheritInfo readType(Class<?> beanType) {
|
||||
|
||||
InheritInfo typeInfo = root.getTypeByClass(beanType);
|
||||
if (typeInfo == null) {
|
||||
throw new PersistenceException("Inheritance type for bean type [" + beanType.getName() + "] was not found?");
|
||||
}
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an EntityBean for this type.
|
||||
*/
|
||||
public EntityBean createEntityBean() {
|
||||
return descriptor.createEntityBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IdBinder for this type.
|
||||
*/
|
||||
public IdBinder getIdBinder() {
|
||||
return descriptor.getIdBinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the type.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the root node of the tree.
|
||||
* <p>
|
||||
* The root has a map of discriminator values to types.
|
||||
* </p>
|
||||
*/
|
||||
public InheritInfo getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent node.
|
||||
*/
|
||||
public InheritInfo getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is abstract node.
|
||||
*/
|
||||
public boolean isAbstract() {
|
||||
return (discriminatorValue == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the root node.
|
||||
*/
|
||||
public boolean isRoot() {
|
||||
return parent == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a discriminator get the inheritance information for this tree.
|
||||
*/
|
||||
public InheritInfo getType(String discValue) {
|
||||
return discMap.get(discValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the InheritInfo for the given bean type.
|
||||
*/
|
||||
private InheritInfo getTypeByClass(Class<?> beanType) {
|
||||
return typeMap.get(beanType.getName());
|
||||
}
|
||||
|
||||
private void registerWithRoot(InheritInfo info) {
|
||||
if (info.getDiscriminatorStringValue() != null) {
|
||||
String stringDiscValue = info.getDiscriminatorStringValue();
|
||||
discMap.put(stringDiscValue, info);
|
||||
}
|
||||
typeMap.put(info.getType().getName(), info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child node.
|
||||
*/
|
||||
public void addChild(InheritInfo childInfo) {
|
||||
children.add(childInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the derived where for the discriminator.
|
||||
*/
|
||||
public String getWhere() {
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column name of the discriminator.
|
||||
*/
|
||||
public String getDiscriminatorColumn() {
|
||||
return discriminatorColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sql type of the discriminator value.
|
||||
*/
|
||||
public int getDiscriminatorType() {
|
||||
return discriminatorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the discriminator column.
|
||||
*/
|
||||
public int getDiscriminatorLength() {
|
||||
return discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the discriminator value for this node.
|
||||
*/
|
||||
public String getDiscriminatorStringValue() {
|
||||
return discriminatorStringValue;
|
||||
}
|
||||
|
||||
public Object getDiscriminatorValue() {
|
||||
return discriminatorValue;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "InheritInfo[" + type.getName() + "] disc[" + discriminatorStringValue + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
/**
|
||||
* Represents the type of a OneToMany or ManyToMany property.
|
||||
*/
|
||||
public class ManyType {
|
||||
|
||||
public static final ManyType JAVA_LIST = new ManyType(Underlying.LIST);
|
||||
public static final ManyType JAVA_SET = new ManyType(Underlying.SET);
|
||||
public static final ManyType JAVA_MAP = new ManyType(Underlying.MAP);
|
||||
|
||||
public enum Underlying {
|
||||
LIST,
|
||||
SET,
|
||||
MAP
|
||||
}
|
||||
|
||||
private final SpiQuery.Type queryType;
|
||||
|
||||
private final Underlying underlying;
|
||||
|
||||
|
||||
public ManyType(Underlying underlying) {
|
||||
this.underlying = underlying;
|
||||
switch (underlying) {
|
||||
case LIST:
|
||||
queryType = SpiQuery.Type.LIST;
|
||||
break;
|
||||
case SET:
|
||||
queryType = SpiQuery.Type.SET;
|
||||
break;
|
||||
|
||||
default:
|
||||
queryType = SpiQuery.Type.MAP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMap() {
|
||||
return Underlying.MAP.equals(underlying);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matching Query type.
|
||||
*/
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying type.
|
||||
*/
|
||||
public Underlying getUnderlying() {
|
||||
return underlying;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
/**
|
||||
* Represents the type of a OneToMany or ManyToMany property.
|
||||
*/
|
||||
public class ManyType {
|
||||
|
||||
public static final ManyType JAVA_LIST = new ManyType(Underlying.LIST);
|
||||
public static final ManyType JAVA_SET = new ManyType(Underlying.SET);
|
||||
public static final ManyType JAVA_MAP = new ManyType(Underlying.MAP);
|
||||
|
||||
public enum Underlying {
|
||||
LIST,
|
||||
SET,
|
||||
MAP
|
||||
}
|
||||
|
||||
private final SpiQuery.Type queryType;
|
||||
|
||||
private final Underlying underlying;
|
||||
|
||||
|
||||
public ManyType(Underlying underlying) {
|
||||
this.underlying = underlying;
|
||||
switch (underlying) {
|
||||
case LIST:
|
||||
queryType = SpiQuery.Type.LIST;
|
||||
break;
|
||||
case SET:
|
||||
queryType = SpiQuery.Type.SET;
|
||||
break;
|
||||
|
||||
default:
|
||||
queryType = SpiQuery.Type.MAP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMap() {
|
||||
return Underlying.MAP.equals(underlying);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matching Query type.
|
||||
*/
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying type.
|
||||
*/
|
||||
public Underlying getUnderlying() {
|
||||
return underlying;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Default implementation for creating BeanControllers.
|
||||
*/
|
||||
public class PersistControllerManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PersistControllerManager.class);
|
||||
|
||||
private final List<BeanPersistController> list;
|
||||
|
||||
public PersistControllerManager(BootupClasses bootupClasses){
|
||||
|
||||
list = bootupClasses.getBeanPersistControllers();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController for a given entity type.
|
||||
*/
|
||||
public void addPersistControllers(DeployBeanDescriptor<?> deployDesc){
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
BeanPersistController c = list.get(i);
|
||||
if (c.isRegisterFor(deployDesc.getBeanType())){
|
||||
logger.debug("BeanPersistController on[" + deployDesc.getFullName() + "] " + c.getClass().getName());
|
||||
deployDesc.addPersistController(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Default implementation for creating BeanControllers.
|
||||
*/
|
||||
public class PersistControllerManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PersistControllerManager.class);
|
||||
|
||||
private final List<BeanPersistController> list;
|
||||
|
||||
public PersistControllerManager(BootupClasses bootupClasses){
|
||||
|
||||
list = bootupClasses.getBeanPersistControllers();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController for a given entity type.
|
||||
*/
|
||||
public void addPersistControllers(DeployBeanDescriptor<?> deployDesc){
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
BeanPersistController c = list.get(i);
|
||||
if (c.isRegisterFor(deployDesc.getBeanType())){
|
||||
logger.debug("BeanPersistController on[" + deployDesc.getFullName() + "] " + c.getClass().getName());
|
||||
deployDesc.addPersistController(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Manages the assignment/registration of BeanPersistListener with their
|
||||
* respective DeployBeanDescriptor's.
|
||||
*/
|
||||
public class PersistListenerManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PersistListenerManager.class);
|
||||
|
||||
private final List<BeanPersistListener> list;
|
||||
|
||||
public PersistListenerManager(BootupClasses bootupClasses) {
|
||||
list = bootupClasses.getBeanPersistListeners();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController for a given entity type.
|
||||
*/
|
||||
public <T> void addPersistListeners(DeployBeanDescriptor<T> deployDesc) {
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
BeanPersistListener listener = list.get(i);
|
||||
if (listener.isRegisterFor(deployDesc.getBeanType())) {
|
||||
logger.debug("BeanPersistListener on[{}] {}", deployDesc.getFullName(), listener.getClass().getName());
|
||||
deployDesc.addPersistListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Manages the assignment/registration of BeanPersistListener with their
|
||||
* respective DeployBeanDescriptor's.
|
||||
*/
|
||||
public class PersistListenerManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PersistListenerManager.class);
|
||||
|
||||
private final List<BeanPersistListener> list;
|
||||
|
||||
public PersistListenerManager(BootupClasses bootupClasses) {
|
||||
list = bootupClasses.getBeanPersistListeners();
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController for a given entity type.
|
||||
*/
|
||||
public <T> void addPersistListeners(DeployBeanDescriptor<T> deployDesc) {
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
BeanPersistListener listener = list.get(i);
|
||||
if (listener.isRegisterFor(deployDesc.getBeanType())) {
|
||||
logger.debug("BeanPersistListener on[{}] {}", deployDesc.getFullName(), listener.getClass().getName());
|
||||
deployDesc.addPersistListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,203 +1,203 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Represents a join to another table.
|
||||
*/
|
||||
public final class TableJoin {
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for
|
||||
* intersection tables (ManyToMany).
|
||||
*/
|
||||
private final boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* The joined table.
|
||||
*/
|
||||
private final String table;
|
||||
|
||||
/**
|
||||
* The type of join as per deployment (cardinality and optionality).
|
||||
*/
|
||||
private final SqlJoinType type;
|
||||
|
||||
/**
|
||||
* The persist cascade info.
|
||||
*/
|
||||
private final BeanCascadeInfo cascadeInfo;
|
||||
|
||||
private final InheritInfo inheritInfo;
|
||||
|
||||
/**
|
||||
* Properties as an array.
|
||||
*/
|
||||
private final BeanProperty[] properties;
|
||||
|
||||
/**
|
||||
* Columns as an array.
|
||||
*/
|
||||
private final TableJoinColumn[] columns;
|
||||
|
||||
/**
|
||||
* A hash that can be used with the query plan.
|
||||
*/
|
||||
private final int queryHash;
|
||||
|
||||
/**
|
||||
* Create a TableJoin.
|
||||
*/
|
||||
public TableJoin(DeployTableJoin deploy, LinkedHashMap<String, BeanProperty> propMap) {
|
||||
|
||||
this.importedPrimaryKey = deploy.isImportedPrimaryKey();
|
||||
this.table = InternString.intern(deploy.getTable());
|
||||
this.type = deploy.getType();
|
||||
this.cascadeInfo = deploy.getCascadeInfo();
|
||||
this.inheritInfo = deploy.getInheritInfo();
|
||||
|
||||
DeployTableJoinColumn[] deployCols = deploy.columns();
|
||||
this.columns = new TableJoinColumn[deployCols.length];
|
||||
for (int i = 0; i < deployCols.length; i++) {
|
||||
this.columns[i] = new TableJoinColumn(deployCols[i]);
|
||||
}
|
||||
|
||||
DeployBeanProperty[] deployProps = deploy.properties();
|
||||
if (deployProps.length > 0 && propMap == null) {
|
||||
throw new NullPointerException("propMap is null?");
|
||||
}
|
||||
|
||||
this.properties = new BeanProperty[deployProps.length];
|
||||
for (int i = 0; i < deployProps.length; i++) {
|
||||
BeanProperty prop = propMap.get(deployProps[i].getName());
|
||||
this.properties[i] = prop;
|
||||
}
|
||||
this.queryHash = calcQueryHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash value for adding to a query plan.
|
||||
*/
|
||||
private int calcQueryHash() {
|
||||
int hc = type.hashCode();
|
||||
hc = hc * 31 + (table == null ? 0 : table.hashCode());
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
hc = hc * 31 + columns[i].queryHash();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash value for adding to a query plan.
|
||||
*/
|
||||
public int queryHash() {
|
||||
return queryHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(30);
|
||||
sb.append(type).append(" ").append(table).append(" ");
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
sb.append(columns[i]).append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
properties[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
|
||||
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
properties[i].load(sqlBeanLoad);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
properties[i].readSet(ctx, bean, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the imported foreign key maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
public TableJoinColumn[] columns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* For secondary table joins returns the properties mapped to that table.
|
||||
*/
|
||||
public BeanProperty[] properties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the joined table name.
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of join. LEFT OUTER JOIN etc.
|
||||
*/
|
||||
public SqlJoinType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this join is a left outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return type == SqlJoinType.OUTER;
|
||||
}
|
||||
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) {
|
||||
|
||||
String[] names = SplitName.split(prefix);
|
||||
String a1 = ctx.getTableAlias(names[0]);
|
||||
String a2 = ctx.getTableAlias(prefix);
|
||||
|
||||
return addJoin(joinType, a1, a2, ctx);
|
||||
}
|
||||
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String a1, String a2, DbSqlContext ctx) {
|
||||
|
||||
String inheritance = inheritInfo != null ? inheritInfo.getWhere() : null;
|
||||
|
||||
String joinLiteral = joinType.getLiteral(type);
|
||||
ctx.addJoin(joinLiteral, table, columns(), a1, a2, inheritance);
|
||||
|
||||
return joinType.autoToOuter(type);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Represents a join to another table.
|
||||
*/
|
||||
public final class TableJoin {
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for
|
||||
* intersection tables (ManyToMany).
|
||||
*/
|
||||
private final boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* The joined table.
|
||||
*/
|
||||
private final String table;
|
||||
|
||||
/**
|
||||
* The type of join as per deployment (cardinality and optionality).
|
||||
*/
|
||||
private final SqlJoinType type;
|
||||
|
||||
/**
|
||||
* The persist cascade info.
|
||||
*/
|
||||
private final BeanCascadeInfo cascadeInfo;
|
||||
|
||||
private final InheritInfo inheritInfo;
|
||||
|
||||
/**
|
||||
* Properties as an array.
|
||||
*/
|
||||
private final BeanProperty[] properties;
|
||||
|
||||
/**
|
||||
* Columns as an array.
|
||||
*/
|
||||
private final TableJoinColumn[] columns;
|
||||
|
||||
/**
|
||||
* A hash that can be used with the query plan.
|
||||
*/
|
||||
private final int queryHash;
|
||||
|
||||
/**
|
||||
* Create a TableJoin.
|
||||
*/
|
||||
public TableJoin(DeployTableJoin deploy, LinkedHashMap<String, BeanProperty> propMap) {
|
||||
|
||||
this.importedPrimaryKey = deploy.isImportedPrimaryKey();
|
||||
this.table = InternString.intern(deploy.getTable());
|
||||
this.type = deploy.getType();
|
||||
this.cascadeInfo = deploy.getCascadeInfo();
|
||||
this.inheritInfo = deploy.getInheritInfo();
|
||||
|
||||
DeployTableJoinColumn[] deployCols = deploy.columns();
|
||||
this.columns = new TableJoinColumn[deployCols.length];
|
||||
for (int i = 0; i < deployCols.length; i++) {
|
||||
this.columns[i] = new TableJoinColumn(deployCols[i]);
|
||||
}
|
||||
|
||||
DeployBeanProperty[] deployProps = deploy.properties();
|
||||
if (deployProps.length > 0 && propMap == null) {
|
||||
throw new NullPointerException("propMap is null?");
|
||||
}
|
||||
|
||||
this.properties = new BeanProperty[deployProps.length];
|
||||
for (int i = 0; i < deployProps.length; i++) {
|
||||
BeanProperty prop = propMap.get(deployProps[i].getName());
|
||||
this.properties[i] = prop;
|
||||
}
|
||||
this.queryHash = calcQueryHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash value for adding to a query plan.
|
||||
*/
|
||||
private int calcQueryHash() {
|
||||
int hc = type.hashCode();
|
||||
hc = hc * 31 + (table == null ? 0 : table.hashCode());
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
hc = hc * 31 + columns[i].queryHash();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash value for adding to a query plan.
|
||||
*/
|
||||
public int queryHash() {
|
||||
return queryHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(30);
|
||||
sb.append(type).append(" ").append(table).append(" ");
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
sb.append(columns[i]).append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
properties[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
|
||||
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
properties[i].load(sqlBeanLoad);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
properties[i].readSet(ctx, bean, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the imported foreign key maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
public TableJoinColumn[] columns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* For secondary table joins returns the properties mapped to that table.
|
||||
*/
|
||||
public BeanProperty[] properties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the joined table name.
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of join. LEFT OUTER JOIN etc.
|
||||
*/
|
||||
public SqlJoinType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this join is a left outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return type == SqlJoinType.OUTER;
|
||||
}
|
||||
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) {
|
||||
|
||||
String[] names = SplitName.split(prefix);
|
||||
String a1 = ctx.getTableAlias(names[0]);
|
||||
String a2 = ctx.getTableAlias(prefix);
|
||||
|
||||
return addJoin(joinType, a1, a2, ctx);
|
||||
}
|
||||
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String a1, String a2, DbSqlContext ctx) {
|
||||
|
||||
String inheritance = inheritInfo != null ? inheritInfo.getWhere() : null;
|
||||
|
||||
String joinLiteral = joinType.getLiteral(type);
|
||||
ctx.addJoin(joinLiteral, table, columns(), a1, a2, inheritance);
|
||||
|
||||
return joinType.autoToOuter(type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
|
||||
/**
|
||||
* A join pair of local and foreign properties.
|
||||
*/
|
||||
public class TableJoinColumn {
|
||||
|
||||
/**
|
||||
* The local database column name.
|
||||
*/
|
||||
private final String localDbColumn;
|
||||
|
||||
/**
|
||||
* The foreign database column name.
|
||||
*/
|
||||
private final String foreignDbColumn;
|
||||
|
||||
private final boolean insertable;
|
||||
|
||||
private final boolean updateable;
|
||||
|
||||
/**
|
||||
* Hash for including in a query plan
|
||||
*/
|
||||
private final int queryHash;
|
||||
|
||||
/**
|
||||
* Create the pair.
|
||||
*/
|
||||
public TableJoinColumn(DeployTableJoinColumn deploy) {
|
||||
this.localDbColumn = InternString.intern(deploy.getLocalDbColumn());
|
||||
this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn());
|
||||
this.insertable = deploy.isInsertable();
|
||||
this.updateable = deploy.isUpdateable();
|
||||
this.queryHash = hashOf(localDbColumn) * 31 + hashOf(foreignDbColumn);
|
||||
}
|
||||
|
||||
private int hashOf(String value) {
|
||||
return (value == null) ? 0 : value.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return localDbColumn+" = "+foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash for including in a query plan.
|
||||
*/
|
||||
public int queryHash() {
|
||||
return queryHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column name.
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local database column name.
|
||||
*/
|
||||
public String getLocalDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return updateable;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
|
||||
/**
|
||||
* A join pair of local and foreign properties.
|
||||
*/
|
||||
public class TableJoinColumn {
|
||||
|
||||
/**
|
||||
* The local database column name.
|
||||
*/
|
||||
private final String localDbColumn;
|
||||
|
||||
/**
|
||||
* The foreign database column name.
|
||||
*/
|
||||
private final String foreignDbColumn;
|
||||
|
||||
private final boolean insertable;
|
||||
|
||||
private final boolean updateable;
|
||||
|
||||
/**
|
||||
* Hash for including in a query plan
|
||||
*/
|
||||
private final int queryHash;
|
||||
|
||||
/**
|
||||
* Create the pair.
|
||||
*/
|
||||
public TableJoinColumn(DeployTableJoinColumn deploy) {
|
||||
this.localDbColumn = InternString.intern(deploy.getLocalDbColumn());
|
||||
this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn());
|
||||
this.insertable = deploy.isInsertable();
|
||||
this.updateable = deploy.isUpdateable();
|
||||
this.queryHash = hashOf(localDbColumn) * 31 + hashOf(foreignDbColumn);
|
||||
}
|
||||
|
||||
private int hashOf(String value) {
|
||||
return (value == null) ? 0 : value.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return localDbColumn+" = "+foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash for including in a query plan.
|
||||
*/
|
||||
public int queryHash() {
|
||||
return queryHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column name.
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local database column name.
|
||||
*/
|
||||
public String getLocalDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return updateable;
|
||||
}
|
||||
}
|
||||
|
||||
+64
-64
@@ -1,64 +1,64 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Types;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Creates "Counter" GeneratedProperty for various types of number.
|
||||
* <p>
|
||||
* Aka, Integer, Long, Short etc.
|
||||
* </p>
|
||||
*/
|
||||
public class CounterFactory {
|
||||
|
||||
final GeneratedCounterInteger integerCounter = new GeneratedCounterInteger();
|
||||
|
||||
final GeneratedCounterLong longCounter = new GeneratedCounterLong();
|
||||
|
||||
public void setCounter(DeployBeanProperty property) {
|
||||
|
||||
property.setGeneratedProperty(createCounter(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the GeneratedProperty based on the property type.
|
||||
*/
|
||||
private GeneratedProperty createCounter(DeployBeanProperty property) {
|
||||
|
||||
Class<?> propType = property.getPropertyType();
|
||||
if (propType.equals(Integer.class) || propType.equals(int.class)) {
|
||||
return integerCounter;
|
||||
}
|
||||
if (propType.equals(Long.class) || propType.equals(long.class)) {
|
||||
return longCounter;
|
||||
}
|
||||
|
||||
int type = getType(propType);
|
||||
return new GeneratedCounter(type);
|
||||
}
|
||||
|
||||
private int getType(Class<?> propType){
|
||||
if (propType.equals(Short.class) || propType.equals(short.class)){
|
||||
return Types.TINYINT;
|
||||
}
|
||||
if (propType.equals(BigDecimal.class)){
|
||||
return Types.DECIMAL;
|
||||
}
|
||||
if (propType.equals(Double.class) || propType.equals(double.class)){
|
||||
return Types.DOUBLE;
|
||||
}
|
||||
if (propType.equals(Float.class) || propType.equals(float.class)){
|
||||
return Types.REAL;
|
||||
}
|
||||
if (propType.equals(BigInteger.class)){
|
||||
return Types.BIGINT;
|
||||
}
|
||||
String msg = "Can not support Counter for type "+propType.getName();
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Types;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Creates "Counter" GeneratedProperty for various types of number.
|
||||
* <p>
|
||||
* Aka, Integer, Long, Short etc.
|
||||
* </p>
|
||||
*/
|
||||
public class CounterFactory {
|
||||
|
||||
final GeneratedCounterInteger integerCounter = new GeneratedCounterInteger();
|
||||
|
||||
final GeneratedCounterLong longCounter = new GeneratedCounterLong();
|
||||
|
||||
public void setCounter(DeployBeanProperty property) {
|
||||
|
||||
property.setGeneratedProperty(createCounter(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the GeneratedProperty based on the property type.
|
||||
*/
|
||||
private GeneratedProperty createCounter(DeployBeanProperty property) {
|
||||
|
||||
Class<?> propType = property.getPropertyType();
|
||||
if (propType.equals(Integer.class) || propType.equals(int.class)) {
|
||||
return integerCounter;
|
||||
}
|
||||
if (propType.equals(Long.class) || propType.equals(long.class)) {
|
||||
return longCounter;
|
||||
}
|
||||
|
||||
int type = getType(propType);
|
||||
return new GeneratedCounter(type);
|
||||
}
|
||||
|
||||
private int getType(Class<?> propType){
|
||||
if (propType.equals(Short.class) || propType.equals(short.class)){
|
||||
return Types.TINYINT;
|
||||
}
|
||||
if (propType.equals(BigDecimal.class)){
|
||||
return Types.DECIMAL;
|
||||
}
|
||||
if (propType.equals(Double.class) || propType.equals(double.class)){
|
||||
return Types.DOUBLE;
|
||||
}
|
||||
if (propType.equals(Float.class) || propType.equals(float.class)){
|
||||
return Types.REAL;
|
||||
}
|
||||
if (propType.equals(BigInteger.class)){
|
||||
return Types.BIGINT;
|
||||
}
|
||||
String msg = "Can not support Counter for type "+propType.getName();
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
+58
-58
@@ -1,58 +1,58 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* A general number counter for various number types.
|
||||
*/
|
||||
public class GeneratedCounter implements GeneratedProperty {
|
||||
|
||||
final int numberType;
|
||||
|
||||
public GeneratedCounter(int numberType) {
|
||||
this.numberType = numberType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a 1.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
Integer i = Integer.valueOf(1);
|
||||
return BasicTypeConverter.convert(i, numberType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the current value by one.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
Number currVal = (Number) prop.getValue(bean);
|
||||
Integer nextVal = Integer.valueOf(currVal.intValue() + 1);
|
||||
return BasicTypeConverter.convert(nextVal, numberType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every update.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert setting initial counter value to 1.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* A general number counter for various number types.
|
||||
*/
|
||||
public class GeneratedCounter implements GeneratedProperty {
|
||||
|
||||
final int numberType;
|
||||
|
||||
public GeneratedCounter(int numberType) {
|
||||
this.numberType = numberType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a 1.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
Integer i = Integer.valueOf(1);
|
||||
return BasicTypeConverter.convert(i, numberType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the current value by one.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
Number currVal = (Number) prop.getValue(bean);
|
||||
Integer nextVal = Integer.valueOf(currVal.intValue() + 1);
|
||||
return BasicTypeConverter.convert(nextVal, numberType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every update.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert setting initial counter value to 1.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+53
-53
@@ -1,53 +1,53 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to create a counter version column for Integer.
|
||||
*/
|
||||
public class GeneratedCounterInteger implements GeneratedProperty {
|
||||
|
||||
public GeneratedCounterInteger() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a 1.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Integer.valueOf(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the current value by one.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
Integer i = (Integer) prop.getValue(bean);
|
||||
return Integer.valueOf(i.intValue() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every update.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert setting initial counter value to 1.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to create a counter version column for Integer.
|
||||
*/
|
||||
public class GeneratedCounterInteger implements GeneratedProperty {
|
||||
|
||||
public GeneratedCounterInteger() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a 1.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Integer.valueOf(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the current value by one.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
Integer i = (Integer) prop.getValue(bean);
|
||||
return Integer.valueOf(i.intValue() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every update.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert setting initial counter value to 1.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+53
-53
@@ -1,53 +1,53 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to create a counter version column for Long.
|
||||
*/
|
||||
public class GeneratedCounterLong implements GeneratedProperty {
|
||||
|
||||
public GeneratedCounterLong() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a 1.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the current value by one.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
Long i = (Long) prop.getValue(bean);
|
||||
return Long.valueOf(i.longValue() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every update.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert setting initial counter value to 1.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to create a counter version column for Long.
|
||||
*/
|
||||
public class GeneratedCounterLong implements GeneratedProperty {
|
||||
|
||||
public GeneratedCounterLong() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns a 1.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the current value by one.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
Long i = (Long) prop.getValue(bean);
|
||||
return Long.valueOf(i.longValue() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every update.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert setting initial counter value to 1.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+50
-50
@@ -1,50 +1,50 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate a (java.util.Date) timestamp when a bean is inserted.
|
||||
*/
|
||||
public class GeneratedInsertDate implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return the current time as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Date(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Just returns the beans original insert timestamp value.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return prop.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate a (java.util.Date) timestamp when a bean is inserted.
|
||||
*/
|
||||
public class GeneratedInsertDate implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return the current time as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Date(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Just returns the beans original insert timestamp value.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return prop.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+48
-48
@@ -1,48 +1,48 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate a (Long) timestamp when a bean is inserted.
|
||||
*/
|
||||
public class GeneratedInsertLong implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return the current time as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Just returns the beans original insert timestamp value.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return prop.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate a (Long) timestamp when a bean is inserted.
|
||||
*/
|
||||
public class GeneratedInsertLong implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return the current time as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Just returns the beans original insert timestamp value.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return prop.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+50
-50
@@ -1,50 +1,50 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate a timestamp when a bean is inserted.
|
||||
*/
|
||||
public class GeneratedInsertTimestamp implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return the current time as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Just returns the beans original insert timestamp value.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return prop.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate a timestamp when a bean is inserted.
|
||||
*/
|
||||
public class GeneratedInsertTimestamp implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return the current time as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Just returns the beans original insert timestamp value.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return prop.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+47
-47
@@ -1,47 +1,47 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate values for a property rather than have then set by the user.
|
||||
* For example generate the update timestamp when a bean is updated.
|
||||
*/
|
||||
public interface GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Get the generated insert value for a specific property of a bean.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean);
|
||||
|
||||
/**
|
||||
* Get the generated update value for a specific property of a bean.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean);
|
||||
|
||||
/**
|
||||
* Return true if this should always be includes in an update statement.
|
||||
* <p>
|
||||
* Used to include GeneratedUpdateTimestamp in dynamic table updates.
|
||||
* </p>
|
||||
*/
|
||||
public boolean includeInUpdate();
|
||||
|
||||
/**
|
||||
* Return true if the property should be included in an update even if
|
||||
* it is not loaded (ie. Last Updated Timestamp).
|
||||
*/
|
||||
public boolean includeInAllUpdates();
|
||||
|
||||
/**
|
||||
* Return true if this should be included in insert statements.
|
||||
*/
|
||||
public boolean includeInInsert();
|
||||
|
||||
/**
|
||||
* Return true if the GeneratedProperty implies the DDL to create the DB
|
||||
* column should have a not null constraint.
|
||||
*/
|
||||
public boolean isDDLNotNullable();
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Used to generate values for a property rather than have then set by the user.
|
||||
* For example generate the update timestamp when a bean is updated.
|
||||
*/
|
||||
public interface GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Get the generated insert value for a specific property of a bean.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean);
|
||||
|
||||
/**
|
||||
* Get the generated update value for a specific property of a bean.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean);
|
||||
|
||||
/**
|
||||
* Return true if this should always be includes in an update statement.
|
||||
* <p>
|
||||
* Used to include GeneratedUpdateTimestamp in dynamic table updates.
|
||||
* </p>
|
||||
*/
|
||||
public boolean includeInUpdate();
|
||||
|
||||
/**
|
||||
* Return true if the property should be included in an update even if
|
||||
* it is not loaded (ie. Last Updated Timestamp).
|
||||
*/
|
||||
public boolean includeInAllUpdates();
|
||||
|
||||
/**
|
||||
* Return true if this should be included in insert statements.
|
||||
*/
|
||||
public boolean includeInInsert();
|
||||
|
||||
/**
|
||||
* Return true if the GeneratedProperty implies the DDL to create the DB
|
||||
* column should have a not null constraint.
|
||||
*/
|
||||
public boolean isDDLNotNullable();
|
||||
|
||||
}
|
||||
|
||||
+65
-65
@@ -1,65 +1,65 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Default implementation of GeneratedPropertyFactory.
|
||||
*/
|
||||
public class GeneratedPropertyFactory {
|
||||
|
||||
CounterFactory counterFactory;
|
||||
|
||||
InsertTimestampFactory insertFactory;
|
||||
|
||||
UpdateTimestampFactory updateFactory;
|
||||
|
||||
HashSet<String> numberTypes = new HashSet<String>();
|
||||
|
||||
public GeneratedPropertyFactory() {
|
||||
counterFactory = new CounterFactory();
|
||||
insertFactory = new InsertTimestampFactory();
|
||||
updateFactory = new UpdateTimestampFactory();
|
||||
|
||||
|
||||
numberTypes.add(Integer.class.getName());
|
||||
numberTypes.add(int.class.getName());
|
||||
numberTypes.add(Long.class.getName());
|
||||
numberTypes.add(long.class.getName());
|
||||
numberTypes.add(Short.class.getName());
|
||||
numberTypes.add(short.class.getName());
|
||||
numberTypes.add(Double.class.getName());
|
||||
numberTypes.add(double.class.getName());
|
||||
numberTypes.add(BigDecimal.class.getName());
|
||||
}
|
||||
|
||||
private boolean isNumberType(String typeClassName) {
|
||||
return numberTypes.contains(typeClassName);
|
||||
}
|
||||
|
||||
public void setVersion(DeployBeanProperty property) {
|
||||
if (isNumberType(property.getPropertyType().getName())) {
|
||||
setCounter(property);
|
||||
} else {
|
||||
setUpdateTimestamp(property);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCounter(DeployBeanProperty property) {
|
||||
|
||||
counterFactory.setCounter(property);
|
||||
}
|
||||
|
||||
public void setInsertTimestamp(DeployBeanProperty property) {
|
||||
|
||||
insertFactory.setInsertTimestamp(property);
|
||||
}
|
||||
|
||||
public void setUpdateTimestamp(DeployBeanProperty property) {
|
||||
|
||||
updateFactory.setUpdateTimestamp(property);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Default implementation of GeneratedPropertyFactory.
|
||||
*/
|
||||
public class GeneratedPropertyFactory {
|
||||
|
||||
CounterFactory counterFactory;
|
||||
|
||||
InsertTimestampFactory insertFactory;
|
||||
|
||||
UpdateTimestampFactory updateFactory;
|
||||
|
||||
HashSet<String> numberTypes = new HashSet<String>();
|
||||
|
||||
public GeneratedPropertyFactory() {
|
||||
counterFactory = new CounterFactory();
|
||||
insertFactory = new InsertTimestampFactory();
|
||||
updateFactory = new UpdateTimestampFactory();
|
||||
|
||||
|
||||
numberTypes.add(Integer.class.getName());
|
||||
numberTypes.add(int.class.getName());
|
||||
numberTypes.add(Long.class.getName());
|
||||
numberTypes.add(long.class.getName());
|
||||
numberTypes.add(Short.class.getName());
|
||||
numberTypes.add(short.class.getName());
|
||||
numberTypes.add(Double.class.getName());
|
||||
numberTypes.add(double.class.getName());
|
||||
numberTypes.add(BigDecimal.class.getName());
|
||||
}
|
||||
|
||||
private boolean isNumberType(String typeClassName) {
|
||||
return numberTypes.contains(typeClassName);
|
||||
}
|
||||
|
||||
public void setVersion(DeployBeanProperty property) {
|
||||
if (isNumberType(property.getPropertyType().getName())) {
|
||||
setCounter(property);
|
||||
} else {
|
||||
setUpdateTimestamp(property);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCounter(DeployBeanProperty property) {
|
||||
|
||||
counterFactory.setCounter(property);
|
||||
}
|
||||
|
||||
public void setInsertTimestamp(DeployBeanProperty property) {
|
||||
|
||||
insertFactory.setInsertTimestamp(property);
|
||||
}
|
||||
|
||||
public void setUpdateTimestamp(DeployBeanProperty property) {
|
||||
|
||||
updateFactory.setUpdateTimestamp(property);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+51
-51
@@ -1,51 +1,51 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Generate a (java.util.Date) Timestamp whenever the bean is inserted or
|
||||
* updated.
|
||||
*/
|
||||
public class GeneratedUpdateDate implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Date(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Date(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* For dynamic table updates make sure this is included.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Generate a (java.util.Date) Timestamp whenever the bean is inserted or
|
||||
* updated.
|
||||
*/
|
||||
public class GeneratedUpdateDate implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Date(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Date(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* For dynamic table updates make sure this is included.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+48
-48
@@ -1,48 +1,48 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Generate a (Long) Timestamp whenever the bean is inserted or updated.
|
||||
*/
|
||||
public class GeneratedUpdateLong implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* For dynamic table updates make sure this is included.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Generate a (Long) Timestamp whenever the bean is inserted or updated.
|
||||
*/
|
||||
public class GeneratedUpdateLong implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return Long.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* For dynamic table updates make sure this is included.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+50
-50
@@ -1,50 +1,50 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Generate a Timestamp whenever the bean is inserted or updated.
|
||||
*/
|
||||
public class GeneratedUpdateTimestamp implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* For dynamic table updates make sure this is included.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Generate a Timestamp whenever the bean is inserted or updated.
|
||||
*/
|
||||
public class GeneratedUpdateTimestamp implements GeneratedProperty {
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return now as a Timestamp.
|
||||
*/
|
||||
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* For dynamic table updates make sure this is included.
|
||||
*/
|
||||
public boolean includeInUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeInAllUpdates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include this in every insert.
|
||||
*/
|
||||
public boolean includeInInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDDLNotNullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+61
-61
@@ -1,61 +1,61 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Helper for creating Insert timestamp GeneratedProperty objects.
|
||||
*/
|
||||
public class InsertTimestampFactory {
|
||||
|
||||
final GeneratedInsertLong longTime = new GeneratedInsertLong();
|
||||
|
||||
Map<Class<?>, GeneratedProperty> map = new HashMap<Class<?>, GeneratedProperty>();
|
||||
|
||||
public InsertTimestampFactory() {
|
||||
map.put(Timestamp.class, new GeneratedInsertTimestamp());
|
||||
map.put(java.util.Date.class, new GeneratedInsertDate());
|
||||
map.put(Long.class, longTime);
|
||||
map.put(long.class, longTime);
|
||||
|
||||
if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) {
|
||||
map.put(LocalDateTime.class, new GeneratedInsertJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedInsertJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedInsertJavaTime.ZonedDT());
|
||||
}
|
||||
if (ClassUtil.isPresent("org.joda.time.LocalDateTime", this.getClass())) {
|
||||
map.put(org.joda.time.LocalDateTime.class, new GeneratedInsertJodaTime.LocalDT());
|
||||
map.put(org.joda.time.DateTime.class, new GeneratedInsertJodaTime.DateTimeDT());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setInsertTimestamp(DeployBeanProperty property) {
|
||||
|
||||
property.setGeneratedProperty(createInsertTimestamp(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the insert GeneratedProperty depending on the property type.
|
||||
*/
|
||||
public GeneratedProperty createInsertTimestamp(DeployBeanProperty property) {
|
||||
|
||||
Class<?> propType = property.getPropertyType();
|
||||
GeneratedProperty generatedProperty = map.get(propType);
|
||||
if (generatedProperty != null) {
|
||||
return generatedProperty;
|
||||
}
|
||||
|
||||
throw new PersistenceException("Generated Insert Timestamp not supported on "+propType.getName());
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Helper for creating Insert timestamp GeneratedProperty objects.
|
||||
*/
|
||||
public class InsertTimestampFactory {
|
||||
|
||||
final GeneratedInsertLong longTime = new GeneratedInsertLong();
|
||||
|
||||
Map<Class<?>, GeneratedProperty> map = new HashMap<Class<?>, GeneratedProperty>();
|
||||
|
||||
public InsertTimestampFactory() {
|
||||
map.put(Timestamp.class, new GeneratedInsertTimestamp());
|
||||
map.put(java.util.Date.class, new GeneratedInsertDate());
|
||||
map.put(Long.class, longTime);
|
||||
map.put(long.class, longTime);
|
||||
|
||||
if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) {
|
||||
map.put(LocalDateTime.class, new GeneratedInsertJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedInsertJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedInsertJavaTime.ZonedDT());
|
||||
}
|
||||
if (ClassUtil.isPresent("org.joda.time.LocalDateTime", this.getClass())) {
|
||||
map.put(org.joda.time.LocalDateTime.class, new GeneratedInsertJodaTime.LocalDT());
|
||||
map.put(org.joda.time.DateTime.class, new GeneratedInsertJodaTime.DateTimeDT());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setInsertTimestamp(DeployBeanProperty property) {
|
||||
|
||||
property.setGeneratedProperty(createInsertTimestamp(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the insert GeneratedProperty depending on the property type.
|
||||
*/
|
||||
public GeneratedProperty createInsertTimestamp(DeployBeanProperty property) {
|
||||
|
||||
Class<?> propType = property.getPropertyType();
|
||||
GeneratedProperty generatedProperty = map.get(propType);
|
||||
if (generatedProperty != null) {
|
||||
return generatedProperty;
|
||||
}
|
||||
|
||||
throw new PersistenceException("Generated Insert Timestamp not supported on "+propType.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+60
-60
@@ -1,60 +1,60 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Helper for creating Update timestamp GeneratedProperty objects.
|
||||
*/
|
||||
public class UpdateTimestampFactory {
|
||||
|
||||
final GeneratedUpdateLong longTime = new GeneratedUpdateLong();
|
||||
|
||||
Map<Class<?>, GeneratedProperty> map = new HashMap<Class<?>, GeneratedProperty>();
|
||||
|
||||
public UpdateTimestampFactory() {
|
||||
map.put(Timestamp.class, new GeneratedUpdateTimestamp());
|
||||
map.put(java.util.Date.class, new GeneratedUpdateDate());
|
||||
map.put(Long.class, longTime);
|
||||
map.put(long.class, longTime);
|
||||
|
||||
if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) {
|
||||
map.put(LocalDateTime.class, new GeneratedUpdateJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedUpdateJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedUpdateJavaTime.ZonedDT());
|
||||
}
|
||||
if (ClassUtil.isPresent("org.joda.time.LocalDateTime", this.getClass())) {
|
||||
map.put(org.joda.time.LocalDateTime.class, new GeneratedUpdateJodaTime.LocalDT());
|
||||
map.put(org.joda.time.DateTime.class, new GeneratedUpdateJodaTime.DateTimeDT());
|
||||
}
|
||||
}
|
||||
|
||||
public void setUpdateTimestamp(DeployBeanProperty property) {
|
||||
|
||||
property.setGeneratedProperty(createUpdateTimestamp(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the update GeneratedProperty depending on the property type.
|
||||
*/
|
||||
protected GeneratedProperty createUpdateTimestamp(DeployBeanProperty property) {
|
||||
|
||||
Class<?> propType = property.getPropertyType();
|
||||
GeneratedProperty generatedProperty = map.get(propType);
|
||||
if (generatedProperty != null) {
|
||||
return generatedProperty;
|
||||
}
|
||||
|
||||
throw new PersistenceException("Generated update Timestamp not supported on "+propType.getName());
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Helper for creating Update timestamp GeneratedProperty objects.
|
||||
*/
|
||||
public class UpdateTimestampFactory {
|
||||
|
||||
final GeneratedUpdateLong longTime = new GeneratedUpdateLong();
|
||||
|
||||
Map<Class<?>, GeneratedProperty> map = new HashMap<Class<?>, GeneratedProperty>();
|
||||
|
||||
public UpdateTimestampFactory() {
|
||||
map.put(Timestamp.class, new GeneratedUpdateTimestamp());
|
||||
map.put(java.util.Date.class, new GeneratedUpdateDate());
|
||||
map.put(Long.class, longTime);
|
||||
map.put(long.class, longTime);
|
||||
|
||||
if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) {
|
||||
map.put(LocalDateTime.class, new GeneratedUpdateJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedUpdateJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedUpdateJavaTime.ZonedDT());
|
||||
}
|
||||
if (ClassUtil.isPresent("org.joda.time.LocalDateTime", this.getClass())) {
|
||||
map.put(org.joda.time.LocalDateTime.class, new GeneratedUpdateJodaTime.LocalDT());
|
||||
map.put(org.joda.time.DateTime.class, new GeneratedUpdateJodaTime.DateTimeDT());
|
||||
}
|
||||
}
|
||||
|
||||
public void setUpdateTimestamp(DeployBeanProperty property) {
|
||||
|
||||
property.setGeneratedProperty(createUpdateTimestamp(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the update GeneratedProperty depending on the property type.
|
||||
*/
|
||||
protected GeneratedProperty createUpdateTimestamp(DeployBeanProperty property) {
|
||||
|
||||
Class<?> propType = property.getPropertyType();
|
||||
GeneratedProperty generatedProperty = map.get(propType);
|
||||
if (generatedProperty != null) {
|
||||
return generatedProperty;
|
||||
}
|
||||
|
||||
throw new PersistenceException("Generated update Timestamp not supported on "+propType.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,407 +1,407 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
|
||||
/**
|
||||
* Bind an Id that is an Embedded bean.
|
||||
*/
|
||||
public final class IdBinderEmbedded implements IdBinder {
|
||||
|
||||
private final BeanPropertyAssocOne<?> embIdProperty;
|
||||
|
||||
private final boolean idInExpandedForm;
|
||||
|
||||
private BeanProperty[] props;
|
||||
|
||||
private BeanDescriptor<?> idDesc;
|
||||
|
||||
private String idInValueSql;
|
||||
|
||||
public IdBinderEmbedded(boolean idInExpandedForm, BeanPropertyAssocOne<?> embIdProperty) {
|
||||
this.idInExpandedForm = idInExpandedForm;
|
||||
this.embIdProperty = embIdProperty;
|
||||
}
|
||||
|
||||
public void initialise() {
|
||||
this.idDesc = embIdProperty.getTargetDescriptor();
|
||||
this.props = embIdProperty.getProperties();
|
||||
this.idInValueSql = idInExpandedForm ? idInExpanded() : idInCompressed();
|
||||
}
|
||||
|
||||
public boolean isIdInExpandedForm() {
|
||||
return idInExpandedForm;
|
||||
}
|
||||
|
||||
private String idInExpanded() {
|
||||
|
||||
StringBuilder sb = new StringBuilder(30);
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
sb.append(idDesc.getBaseTableAlias());
|
||||
sb.append(".");
|
||||
sb.append(props[i].getDbColumn());
|
||||
sb.append("=?");
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String idInCompressed() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("?");
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanProperty getBeanProperty() {
|
||||
return embIdProperty;
|
||||
}
|
||||
|
||||
public String getOrderBy(String pathPrefix, boolean ascending) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
if (pathPrefix != null) {
|
||||
sb.append(pathPrefix).append(".");
|
||||
}
|
||||
|
||||
sb.append(embIdProperty.getName()).append(".");
|
||||
sb.append(props[i].getName());
|
||||
if (!ascending) {
|
||||
sb.append(" desc");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public BeanDescriptor<?> getIdBeanDescriptor() {
|
||||
return idDesc;
|
||||
}
|
||||
|
||||
public int getPropertyCount() {
|
||||
return props.length;
|
||||
}
|
||||
|
||||
public String getIdProperty() {
|
||||
return embIdProperty.getName();
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
|
||||
prefix = SplitName.add(prefix, embIdProperty.getName());
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
props[i].buildSelectExpressionChain(prefix, selectChain);
|
||||
}
|
||||
}
|
||||
|
||||
public BeanProperty findBeanProperty(String dbColumnName) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (dbColumnName.equalsIgnoreCase(props[i].getDbColumn())) {
|
||||
return props[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isComplexId() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getDefaultOrderBy() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
sb.append(embIdProperty.getName());
|
||||
sb.append(".");
|
||||
sb.append(props[i].getName());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public BeanProperty[] getProperties() {
|
||||
return props;
|
||||
}
|
||||
|
||||
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
request.addBindValue(props[i].getValue((EntityBean) value));
|
||||
}
|
||||
}
|
||||
|
||||
public String getIdInValueExprDelete(int size) {
|
||||
if (!idInExpandedForm) {
|
||||
return getIdInValueExpr(size);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (j > 0) {
|
||||
sb.append(" or ");
|
||||
}
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
sb.append(props[i].getDbColumn());
|
||||
sb.append("=?");
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append(") ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getIdInValueExpr(int size) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (!idInExpandedForm) {
|
||||
sb.append(" in");
|
||||
}
|
||||
sb.append(" (");
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
if (idInExpandedForm) {
|
||||
sb.append(" or ");
|
||||
} else {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append(idInValueSql);
|
||||
}
|
||||
sb.append(") ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getIdInValueExpr() {
|
||||
return idInValueSql;
|
||||
}
|
||||
|
||||
public Object[] getIdValues(EntityBean bean) {
|
||||
Object val = embIdProperty.getValue(bean);
|
||||
Object[] bindvalues = new Object[props.length];
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
bindvalues[i] = props[i].getValue((EntityBean) val);
|
||||
}
|
||||
return bindvalues;
|
||||
}
|
||||
|
||||
public Object[] getBindValues(Object value) {
|
||||
|
||||
Object[] bindvalues = new Object[props.length];
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
bindvalues[i] = props[i].getValue((EntityBean) value);
|
||||
}
|
||||
return bindvalues;
|
||||
}
|
||||
|
||||
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object embFieldValue = props[i].getValue((EntityBean) value);
|
||||
sqlUpdate.addParameter(embFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void bindId(DataBind dataBind, Object value) throws SQLException {
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object embFieldValue = props[i].getValue((EntityBean) value);
|
||||
props[i].bind(dataBind, embFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readData(DataInput dataInput) throws IOException {
|
||||
|
||||
EntityBean embId = idDesc.createEntityBean();
|
||||
boolean notNull = true;
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object value = props[i].readData(dataInput);
|
||||
props[i].setValue(embId, value);
|
||||
if (value == null) {
|
||||
notNull = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (notNull) {
|
||||
return embId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeData(DataOutput dataOutput, Object idValue) throws IOException {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object embFieldValue = props[i].getValue((EntityBean) idValue);
|
||||
props[i].writeData(dataOutput, embFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
props[i].loadIgnore(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
EntityBean embId = idDesc.createEntityBean();
|
||||
boolean notNull = true;
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object value = props[i].readSet(ctx, embId, null);
|
||||
if (value == null) {
|
||||
notNull = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (notNull) {
|
||||
return embId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
|
||||
Object embId = read(ctx);
|
||||
if (embId != null) {
|
||||
embIdProperty.setValue(bean, embId);
|
||||
return embId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
props[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(props[i].getName());
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
|
||||
sb.append(embIdProperty.getName());
|
||||
sb.append(".");
|
||||
sb.append(props[i].getName());
|
||||
sb.append(operator);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getBindIdSql(String baseTableAlias) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
if (baseTableAlias != null) {
|
||||
sb.append(baseTableAlias);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(props[i].getDbColumn());
|
||||
sb.append(" = ? ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getBindIdInSql(String baseTableAlias) {
|
||||
|
||||
if (idInExpandedForm) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
if (baseTableAlias != null) {
|
||||
sb.append(baseTableAlias);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(props[i].getDbColumn());
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Object convertSetId(Object idValue, EntityBean bean) {
|
||||
|
||||
// can not cast/convert if it is embedded
|
||||
if (bean != null) {
|
||||
// support PropertyChangeSupport
|
||||
embIdProperty.setValueIntercept(bean, idValue);
|
||||
}
|
||||
|
||||
return idValue;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
|
||||
/**
|
||||
* Bind an Id that is an Embedded bean.
|
||||
*/
|
||||
public final class IdBinderEmbedded implements IdBinder {
|
||||
|
||||
private final BeanPropertyAssocOne<?> embIdProperty;
|
||||
|
||||
private final boolean idInExpandedForm;
|
||||
|
||||
private BeanProperty[] props;
|
||||
|
||||
private BeanDescriptor<?> idDesc;
|
||||
|
||||
private String idInValueSql;
|
||||
|
||||
public IdBinderEmbedded(boolean idInExpandedForm, BeanPropertyAssocOne<?> embIdProperty) {
|
||||
this.idInExpandedForm = idInExpandedForm;
|
||||
this.embIdProperty = embIdProperty;
|
||||
}
|
||||
|
||||
public void initialise() {
|
||||
this.idDesc = embIdProperty.getTargetDescriptor();
|
||||
this.props = embIdProperty.getProperties();
|
||||
this.idInValueSql = idInExpandedForm ? idInExpanded() : idInCompressed();
|
||||
}
|
||||
|
||||
public boolean isIdInExpandedForm() {
|
||||
return idInExpandedForm;
|
||||
}
|
||||
|
||||
private String idInExpanded() {
|
||||
|
||||
StringBuilder sb = new StringBuilder(30);
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
sb.append(idDesc.getBaseTableAlias());
|
||||
sb.append(".");
|
||||
sb.append(props[i].getDbColumn());
|
||||
sb.append("=?");
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String idInCompressed() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("?");
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanProperty getBeanProperty() {
|
||||
return embIdProperty;
|
||||
}
|
||||
|
||||
public String getOrderBy(String pathPrefix, boolean ascending) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
if (pathPrefix != null) {
|
||||
sb.append(pathPrefix).append(".");
|
||||
}
|
||||
|
||||
sb.append(embIdProperty.getName()).append(".");
|
||||
sb.append(props[i].getName());
|
||||
if (!ascending) {
|
||||
sb.append(" desc");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public BeanDescriptor<?> getIdBeanDescriptor() {
|
||||
return idDesc;
|
||||
}
|
||||
|
||||
public int getPropertyCount() {
|
||||
return props.length;
|
||||
}
|
||||
|
||||
public String getIdProperty() {
|
||||
return embIdProperty.getName();
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
|
||||
prefix = SplitName.add(prefix, embIdProperty.getName());
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
props[i].buildSelectExpressionChain(prefix, selectChain);
|
||||
}
|
||||
}
|
||||
|
||||
public BeanProperty findBeanProperty(String dbColumnName) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (dbColumnName.equalsIgnoreCase(props[i].getDbColumn())) {
|
||||
return props[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isComplexId() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getDefaultOrderBy() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
sb.append(embIdProperty.getName());
|
||||
sb.append(".");
|
||||
sb.append(props[i].getName());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public BeanProperty[] getProperties() {
|
||||
return props;
|
||||
}
|
||||
|
||||
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
request.addBindValue(props[i].getValue((EntityBean) value));
|
||||
}
|
||||
}
|
||||
|
||||
public String getIdInValueExprDelete(int size) {
|
||||
if (!idInExpandedForm) {
|
||||
return getIdInValueExpr(size);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (j > 0) {
|
||||
sb.append(" or ");
|
||||
}
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
sb.append(props[i].getDbColumn());
|
||||
sb.append("=?");
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append(") ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getIdInValueExpr(int size) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (!idInExpandedForm) {
|
||||
sb.append(" in");
|
||||
}
|
||||
sb.append(" (");
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
if (idInExpandedForm) {
|
||||
sb.append(" or ");
|
||||
} else {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append(idInValueSql);
|
||||
}
|
||||
sb.append(") ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getIdInValueExpr() {
|
||||
return idInValueSql;
|
||||
}
|
||||
|
||||
public Object[] getIdValues(EntityBean bean) {
|
||||
Object val = embIdProperty.getValue(bean);
|
||||
Object[] bindvalues = new Object[props.length];
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
bindvalues[i] = props[i].getValue((EntityBean) val);
|
||||
}
|
||||
return bindvalues;
|
||||
}
|
||||
|
||||
public Object[] getBindValues(Object value) {
|
||||
|
||||
Object[] bindvalues = new Object[props.length];
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
bindvalues[i] = props[i].getValue((EntityBean) value);
|
||||
}
|
||||
return bindvalues;
|
||||
}
|
||||
|
||||
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object embFieldValue = props[i].getValue((EntityBean) value);
|
||||
sqlUpdate.addParameter(embFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void bindId(DataBind dataBind, Object value) throws SQLException {
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object embFieldValue = props[i].getValue((EntityBean) value);
|
||||
props[i].bind(dataBind, embFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readData(DataInput dataInput) throws IOException {
|
||||
|
||||
EntityBean embId = idDesc.createEntityBean();
|
||||
boolean notNull = true;
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object value = props[i].readData(dataInput);
|
||||
props[i].setValue(embId, value);
|
||||
if (value == null) {
|
||||
notNull = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (notNull) {
|
||||
return embId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeData(DataOutput dataOutput, Object idValue) throws IOException {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object embFieldValue = props[i].getValue((EntityBean) idValue);
|
||||
props[i].writeData(dataOutput, embFieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
props[i].loadIgnore(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
EntityBean embId = idDesc.createEntityBean();
|
||||
boolean notNull = true;
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object value = props[i].readSet(ctx, embId, null);
|
||||
if (value == null) {
|
||||
notNull = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (notNull) {
|
||||
return embId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
|
||||
Object embId = read(ctx);
|
||||
if (embId != null) {
|
||||
embIdProperty.setValue(bean, embId);
|
||||
return embId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
props[i].appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(props[i].getName());
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
|
||||
sb.append(embIdProperty.getName());
|
||||
sb.append(".");
|
||||
sb.append(props[i].getName());
|
||||
sb.append(operator);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getBindIdSql(String baseTableAlias) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
if (baseTableAlias != null) {
|
||||
sb.append(baseTableAlias);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(props[i].getDbColumn());
|
||||
sb.append(" = ? ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getBindIdInSql(String baseTableAlias) {
|
||||
|
||||
if (idInExpandedForm) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
if (baseTableAlias != null) {
|
||||
sb.append(baseTableAlias);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(props[i].getDbColumn());
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Object convertSetId(Object idValue, EntityBean bean) {
|
||||
|
||||
// can not cast/convert if it is embedded
|
||||
if (bean != null) {
|
||||
// support PropertyChangeSupport
|
||||
embIdProperty.setValueIntercept(bean, idValue);
|
||||
}
|
||||
|
||||
return idValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Creates the appropriate IdConvertSet depending on the type of Id property(s).
|
||||
*/
|
||||
public class IdBinderFactory {
|
||||
|
||||
private static final IdBinderEmpty EMPTY = new IdBinderEmpty();
|
||||
|
||||
private final boolean idInExpandedForm;
|
||||
|
||||
public IdBinderFactory(boolean idInExpandedForm) {
|
||||
this.idInExpandedForm = idInExpandedForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the IdConvertSet for the given type of Id properties.
|
||||
*/
|
||||
public IdBinder createIdBinder(BeanProperty id) {
|
||||
|
||||
if (id == null){
|
||||
// for report type beans that don't need an id
|
||||
return EMPTY;
|
||||
|
||||
}
|
||||
if (id.isEmbedded()){
|
||||
return new IdBinderEmbedded(idInExpandedForm, (BeanPropertyAssocOne<?>)id);
|
||||
} else {
|
||||
return new IdBinderSimple(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Creates the appropriate IdConvertSet depending on the type of Id property(s).
|
||||
*/
|
||||
public class IdBinderFactory {
|
||||
|
||||
private static final IdBinderEmpty EMPTY = new IdBinderEmpty();
|
||||
|
||||
private final boolean idInExpandedForm;
|
||||
|
||||
public IdBinderFactory(boolean idInExpandedForm) {
|
||||
this.idInExpandedForm = idInExpandedForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the IdConvertSet for the given type of Id properties.
|
||||
*/
|
||||
public IdBinder createIdBinder(BeanProperty id) {
|
||||
|
||||
if (id == null){
|
||||
// for report type beans that don't need an id
|
||||
return EMPTY;
|
||||
|
||||
}
|
||||
if (id.isEmbedded()){
|
||||
return new IdBinderEmbedded(idInExpandedForm, (BeanPropertyAssocOne<?>)id);
|
||||
} else {
|
||||
return new IdBinderSimple(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,217 +1,217 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
/**
|
||||
* Bind an Id where the Id is made of a single property (not embedded).
|
||||
*/
|
||||
public final class IdBinderSimple implements IdBinder {
|
||||
|
||||
private final BeanProperty idProperty;
|
||||
|
||||
private final String bindIdSql;
|
||||
|
||||
private final Class<?> expectedType;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final ScalarType scalarType;
|
||||
|
||||
public IdBinderSimple(BeanProperty idProperty) {
|
||||
this.idProperty = idProperty;
|
||||
this.scalarType = idProperty.getScalarType();
|
||||
this.expectedType = idProperty.getPropertyType();
|
||||
bindIdSql = InternString.intern(idProperty.getDbColumn()+" = ? ");
|
||||
}
|
||||
|
||||
public void initialise(){
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public boolean isIdInExpandedForm() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getOrderBy(String pathPrefix, boolean ascending) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (pathPrefix != null) {
|
||||
sb.append(pathPrefix).append(".");
|
||||
}
|
||||
sb.append(idProperty.getName());
|
||||
if (!ascending) {
|
||||
sb.append(" desc");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
|
||||
idProperty.buildSelectExpressionChain(prefix, selectChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1.
|
||||
*/
|
||||
public int getPropertyCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanProperty getBeanProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
public String getIdProperty() {
|
||||
return idProperty.getName();
|
||||
}
|
||||
|
||||
public BeanProperty findBeanProperty(String dbColumnName) {
|
||||
if (dbColumnName.equalsIgnoreCase(idProperty.getDbColumn())){
|
||||
return idProperty;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isComplexId(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDefaultOrderBy() {
|
||||
return idProperty.getName();
|
||||
}
|
||||
|
||||
public String getBindIdInSql(String baseTableAlias) {
|
||||
if (baseTableAlias == null) {
|
||||
return idProperty.getDbColumn();
|
||||
} else {
|
||||
return baseTableAlias + "." + idProperty.getDbColumn();
|
||||
}
|
||||
}
|
||||
|
||||
public String getBindIdSql(String baseTableAlias) {
|
||||
if (baseTableAlias == null) {
|
||||
return bindIdSql;
|
||||
} else {
|
||||
return baseTableAlias + "." + bindIdSql;
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] getIdValues(EntityBean bean) {
|
||||
return new Object[] { idProperty.getValue(bean) };
|
||||
}
|
||||
|
||||
public Object[] getBindValues(Object idValue) {
|
||||
return new Object[] { idValue };
|
||||
}
|
||||
|
||||
public String getIdInValueExprDelete(int size) {
|
||||
return getIdInValueExpr(size);
|
||||
}
|
||||
|
||||
public String getIdInValueExpr(int size) {
|
||||
StringBuilder sb = new StringBuilder(2 * size + 10);
|
||||
sb.append(" in");
|
||||
sb.append(" (?");
|
||||
for (int i = 1; i < size; i++) {
|
||||
sb.append(",?");
|
||||
}
|
||||
sb.append(") ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
|
||||
value = convertSetId(value, null);
|
||||
request.addBindValue(value);
|
||||
}
|
||||
|
||||
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
|
||||
sqlUpdate.addParameter(value);
|
||||
}
|
||||
|
||||
public void bindId(DataBind dataBind, Object value) throws SQLException {
|
||||
if (!value.getClass().equals(expectedType)) {
|
||||
value = scalarType.toBeanType(value);
|
||||
}
|
||||
idProperty.bind(dataBind, value);
|
||||
}
|
||||
|
||||
public void writeData(DataOutput os, Object value) throws IOException {
|
||||
idProperty.writeData(os, value);
|
||||
}
|
||||
|
||||
public Object readData(DataInput is) throws IOException {
|
||||
return idProperty.readData(is);
|
||||
}
|
||||
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
idProperty.loadIgnore(ctx);
|
||||
}
|
||||
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
Object id = idProperty.read(ctx);
|
||||
if (id != null) {
|
||||
idProperty.setValue(bean, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
return idProperty.read(ctx);
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
idProperty.appendSelect(ctx, subQuery);
|
||||
}
|
||||
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(idProperty.getName());
|
||||
sb.append(operator);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(idProperty.getName());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Object convertSetId(Object idValue, EntityBean bean) {
|
||||
|
||||
if (!idValue.getClass().equals(expectedType)) {
|
||||
idValue = scalarType.toBeanType(idValue);
|
||||
}
|
||||
|
||||
if (bean != null) {
|
||||
// support PropertyChangeSupport
|
||||
idProperty.setValueIntercept(bean, idValue);
|
||||
}
|
||||
|
||||
return idValue;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
/**
|
||||
* Bind an Id where the Id is made of a single property (not embedded).
|
||||
*/
|
||||
public final class IdBinderSimple implements IdBinder {
|
||||
|
||||
private final BeanProperty idProperty;
|
||||
|
||||
private final String bindIdSql;
|
||||
|
||||
private final Class<?> expectedType;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final ScalarType scalarType;
|
||||
|
||||
public IdBinderSimple(BeanProperty idProperty) {
|
||||
this.idProperty = idProperty;
|
||||
this.scalarType = idProperty.getScalarType();
|
||||
this.expectedType = idProperty.getPropertyType();
|
||||
bindIdSql = InternString.intern(idProperty.getDbColumn()+" = ? ");
|
||||
}
|
||||
|
||||
public void initialise(){
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public boolean isIdInExpandedForm() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getOrderBy(String pathPrefix, boolean ascending) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (pathPrefix != null) {
|
||||
sb.append(pathPrefix).append(".");
|
||||
}
|
||||
sb.append(idProperty.getName());
|
||||
if (!ascending) {
|
||||
sb.append(" desc");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
|
||||
idProperty.buildSelectExpressionChain(prefix, selectChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1.
|
||||
*/
|
||||
public int getPropertyCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanProperty getBeanProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
public String getIdProperty() {
|
||||
return idProperty.getName();
|
||||
}
|
||||
|
||||
public BeanProperty findBeanProperty(String dbColumnName) {
|
||||
if (dbColumnName.equalsIgnoreCase(idProperty.getDbColumn())){
|
||||
return idProperty;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isComplexId(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDefaultOrderBy() {
|
||||
return idProperty.getName();
|
||||
}
|
||||
|
||||
public String getBindIdInSql(String baseTableAlias) {
|
||||
if (baseTableAlias == null) {
|
||||
return idProperty.getDbColumn();
|
||||
} else {
|
||||
return baseTableAlias + "." + idProperty.getDbColumn();
|
||||
}
|
||||
}
|
||||
|
||||
public String getBindIdSql(String baseTableAlias) {
|
||||
if (baseTableAlias == null) {
|
||||
return bindIdSql;
|
||||
} else {
|
||||
return baseTableAlias + "." + bindIdSql;
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] getIdValues(EntityBean bean) {
|
||||
return new Object[] { idProperty.getValue(bean) };
|
||||
}
|
||||
|
||||
public Object[] getBindValues(Object idValue) {
|
||||
return new Object[] { idValue };
|
||||
}
|
||||
|
||||
public String getIdInValueExprDelete(int size) {
|
||||
return getIdInValueExpr(size);
|
||||
}
|
||||
|
||||
public String getIdInValueExpr(int size) {
|
||||
StringBuilder sb = new StringBuilder(2 * size + 10);
|
||||
sb.append(" in");
|
||||
sb.append(" (?");
|
||||
for (int i = 1; i < size; i++) {
|
||||
sb.append(",?");
|
||||
}
|
||||
sb.append(") ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
|
||||
value = convertSetId(value, null);
|
||||
request.addBindValue(value);
|
||||
}
|
||||
|
||||
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
|
||||
sqlUpdate.addParameter(value);
|
||||
}
|
||||
|
||||
public void bindId(DataBind dataBind, Object value) throws SQLException {
|
||||
if (!value.getClass().equals(expectedType)) {
|
||||
value = scalarType.toBeanType(value);
|
||||
}
|
||||
idProperty.bind(dataBind, value);
|
||||
}
|
||||
|
||||
public void writeData(DataOutput os, Object value) throws IOException {
|
||||
idProperty.writeData(os, value);
|
||||
}
|
||||
|
||||
public Object readData(DataInput is) throws IOException {
|
||||
return idProperty.readData(is);
|
||||
}
|
||||
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
idProperty.loadIgnore(ctx);
|
||||
}
|
||||
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
Object id = idProperty.read(ctx);
|
||||
if (id != null) {
|
||||
idProperty.setValue(bean, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
return idProperty.read(ctx);
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
idProperty.appendSelect(ctx, subQuery);
|
||||
}
|
||||
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(idProperty.getName());
|
||||
sb.append(operator);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append(".");
|
||||
}
|
||||
sb.append(idProperty.getName());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Object convertSetId(Object idValue, EntityBean bean) {
|
||||
|
||||
if (!idValue.getClass().equals(expectedType)) {
|
||||
idValue = scalarType.toBeanType(idValue);
|
||||
}
|
||||
|
||||
if (bean != null) {
|
||||
// support PropertyChangeSupport
|
||||
idProperty.setValueIntercept(bean, idValue);
|
||||
}
|
||||
|
||||
return idValue;
|
||||
}
|
||||
}
|
||||
|
||||
+913
-913
File diff suppressed because it is too large
Load Diff
@@ -1,42 +1,42 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Collects Deployment information on Embedded beans.
|
||||
* <p>
|
||||
* Typically collects the overridden column names mapped
|
||||
* to the Embedded bean.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployBeanEmbedded {
|
||||
|
||||
/**
|
||||
* A map of property names to dbColumns.
|
||||
*/
|
||||
Map<String,String> propMap = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Set a property name to use a specific dbColumn.
|
||||
*/
|
||||
public void put(String propertyName, String dbCoumn){
|
||||
propMap.put(propertyName, dbCoumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Map of property names to dbColumns.
|
||||
*/
|
||||
public void putAll(Map<String,String> propertyColumnMap){
|
||||
propMap.putAll(propertyColumnMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of property names to dbColumns.
|
||||
*/
|
||||
public Map<String, String> getPropertyColumnMap() {
|
||||
return propMap;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Collects Deployment information on Embedded beans.
|
||||
* <p>
|
||||
* Typically collects the overridden column names mapped
|
||||
* to the Embedded bean.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployBeanEmbedded {
|
||||
|
||||
/**
|
||||
* A map of property names to dbColumns.
|
||||
*/
|
||||
Map<String,String> propMap = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Set a property name to use a specific dbColumn.
|
||||
*/
|
||||
public void put(String propertyName, String dbCoumn){
|
||||
propMap.put(propertyName, dbCoumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Map of property names to dbColumns.
|
||||
*/
|
||||
public void putAll(Map<String,String> propertyColumnMap){
|
||||
propMap.putAll(propertyColumnMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of property names to dbColumns.
|
||||
*/
|
||||
public Map<String, String> getPropertyColumnMap() {
|
||||
return propMap;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+951
-951
File diff suppressed because it is too large
Load Diff
+156
-156
@@ -1,156 +1,156 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
|
||||
/**
|
||||
* Abstract base for properties mapped to an associated bean, list, set or map.
|
||||
*/
|
||||
public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
|
||||
|
||||
/**
|
||||
* The type of the joined bean.
|
||||
*/
|
||||
Class<T> targetType;
|
||||
|
||||
/**
|
||||
* Persist settings.
|
||||
*/
|
||||
BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
/**
|
||||
* The join table information.
|
||||
*/
|
||||
BeanTable beanTable;
|
||||
|
||||
/**
|
||||
* Join between the beans.
|
||||
*/
|
||||
DeployTableJoin tableJoin = new DeployTableJoin();
|
||||
|
||||
/**
|
||||
* Whether the associated join type should be an outer join.
|
||||
*/
|
||||
boolean isOuterJoin = false;
|
||||
|
||||
/**
|
||||
* Literal added to where clause of lazy loading query.
|
||||
*/
|
||||
String extraWhere;
|
||||
|
||||
/**
|
||||
* From the deployment mappedBy attribute.
|
||||
*/
|
||||
String mappedBy;
|
||||
|
||||
/**
|
||||
* Construct the property.
|
||||
*/
|
||||
public DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType, null, null);
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
@Override
|
||||
public boolean isScalar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the target.
|
||||
* <p>
|
||||
* This is the class of the associated bean, or beans contained in a list,
|
||||
* set or map.
|
||||
* </p>
|
||||
*/
|
||||
public Class<T> getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if this association should use an Outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return isOuterJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this bean should use an outer join.
|
||||
*/
|
||||
public void setOuterJoin(boolean isOuterJoin) {
|
||||
this.isOuterJoin = isOuterJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a literal expression that is added to the query that lazy loads
|
||||
* the collection.
|
||||
*/
|
||||
public String getExtraWhere() {
|
||||
return extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a literal expression to add to the query that lazy loads the
|
||||
* collection.
|
||||
*/
|
||||
public void setExtraWhere(String extraWhere) {
|
||||
this.extraWhere = extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the join to use for the bean.
|
||||
*/
|
||||
public DeployTableJoin getTableJoin() {
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanTable for this association.
|
||||
* <p>
|
||||
* This has the table name which is used to determine the relationship for
|
||||
* this association.
|
||||
* </p>
|
||||
*/
|
||||
public BeanTable getBeanTable() {
|
||||
return beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean table.
|
||||
*/
|
||||
public void setBeanTable(BeanTable beanTable) {
|
||||
this.beanTable = beanTable;
|
||||
getTableJoin().setTable(beanTable.getBaseTable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the mappedBy deployment attribute.
|
||||
* <p>
|
||||
* This is the name of the property in the 'detail' bean that maps back to
|
||||
* this 'master' bean.
|
||||
* </p>
|
||||
*/
|
||||
public String getMappedBy() {
|
||||
return mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mappedBy deployment attribute.
|
||||
*/
|
||||
public void setMappedBy(String mappedBy) {
|
||||
if (!"".equals(mappedBy)) {
|
||||
this.mappedBy = mappedBy;
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
|
||||
/**
|
||||
* Abstract base for properties mapped to an associated bean, list, set or map.
|
||||
*/
|
||||
public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
|
||||
|
||||
/**
|
||||
* The type of the joined bean.
|
||||
*/
|
||||
Class<T> targetType;
|
||||
|
||||
/**
|
||||
* Persist settings.
|
||||
*/
|
||||
BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
/**
|
||||
* The join table information.
|
||||
*/
|
||||
BeanTable beanTable;
|
||||
|
||||
/**
|
||||
* Join between the beans.
|
||||
*/
|
||||
DeployTableJoin tableJoin = new DeployTableJoin();
|
||||
|
||||
/**
|
||||
* Whether the associated join type should be an outer join.
|
||||
*/
|
||||
boolean isOuterJoin = false;
|
||||
|
||||
/**
|
||||
* Literal added to where clause of lazy loading query.
|
||||
*/
|
||||
String extraWhere;
|
||||
|
||||
/**
|
||||
* From the deployment mappedBy attribute.
|
||||
*/
|
||||
String mappedBy;
|
||||
|
||||
/**
|
||||
* Construct the property.
|
||||
*/
|
||||
public DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType, null, null);
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false.
|
||||
*/
|
||||
@Override
|
||||
public boolean isScalar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the target.
|
||||
* <p>
|
||||
* This is the class of the associated bean, or beans contained in a list,
|
||||
* set or map.
|
||||
* </p>
|
||||
*/
|
||||
public Class<T> getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if this association should use an Outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return isOuterJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this bean should use an outer join.
|
||||
*/
|
||||
public void setOuterJoin(boolean isOuterJoin) {
|
||||
this.isOuterJoin = isOuterJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a literal expression that is added to the query that lazy loads
|
||||
* the collection.
|
||||
*/
|
||||
public String getExtraWhere() {
|
||||
return extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a literal expression to add to the query that lazy loads the
|
||||
* collection.
|
||||
*/
|
||||
public void setExtraWhere(String extraWhere) {
|
||||
this.extraWhere = extraWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the join to use for the bean.
|
||||
*/
|
||||
public DeployTableJoin getTableJoin() {
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanTable for this association.
|
||||
* <p>
|
||||
* This has the table name which is used to determine the relationship for
|
||||
* this association.
|
||||
* </p>
|
||||
*/
|
||||
public BeanTable getBeanTable() {
|
||||
return beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean table.
|
||||
*/
|
||||
public void setBeanTable(BeanTable beanTable) {
|
||||
this.beanTable = beanTable;
|
||||
getTableJoin().setTable(beanTable.getBaseTable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the mappedBy deployment attribute.
|
||||
* <p>
|
||||
* This is the name of the property in the 'detail' bean that maps back to
|
||||
* this 'master' bean.
|
||||
* </p>
|
||||
*/
|
||||
public String getMappedBy() {
|
||||
return mappedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mappedBy deployment attribute.
|
||||
*/
|
||||
public void setMappedBy(String mappedBy) {
|
||||
if (!"".equals(mappedBy)) {
|
||||
this.mappedBy = mappedBy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+194
-194
@@ -1,194 +1,194 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
/**
|
||||
* Property mapped to a List Set or Map.
|
||||
*/
|
||||
public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
|
||||
|
||||
ModifyListenMode modifyListenMode = ModifyListenMode.NONE;
|
||||
|
||||
/**
|
||||
* Flag to indicate manyToMany relationship.
|
||||
*/
|
||||
boolean manyToMany;
|
||||
|
||||
/**
|
||||
* Flag to indicate this is a unidirectional relationship.
|
||||
*/
|
||||
boolean unidirectional;
|
||||
|
||||
/**
|
||||
* Join for manyToMany intersection table.
|
||||
*/
|
||||
DeployTableJoin intersectionJoin;
|
||||
|
||||
/**
|
||||
* For ManyToMany this is the Inverse join used to build reference queries.
|
||||
*/
|
||||
DeployTableJoin inverseJoin;
|
||||
|
||||
String fetchOrderBy;
|
||||
|
||||
String mapKey;
|
||||
|
||||
/**
|
||||
* The type of the many, set, list or map.
|
||||
*/
|
||||
ManyType manyType;
|
||||
|
||||
/**
|
||||
* Create this property.
|
||||
*/
|
||||
public DeployBeanPropertyAssocMany(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
|
||||
super(desc, targetType);
|
||||
this.manyType = manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* When generics is not used for manyType you can specify via annotations.
|
||||
* <p>
|
||||
* Really only expect this for Scala due to a Scala compiler bug at the moment.
|
||||
* Otherwise I'd probably not bother support this.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetType(Class<?> cls){
|
||||
this.targetType = (Class<T>)cls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the many type.
|
||||
*/
|
||||
public ManyType getManyType() {
|
||||
return manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is many to many.
|
||||
*/
|
||||
public boolean isManyToMany() {
|
||||
return manyToMany;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a many to many.
|
||||
*/
|
||||
public void setManyToMany(boolean isManyToMany) {
|
||||
this.manyToMany = isManyToMany;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mode for listening to changes to the List Set or Map.
|
||||
*/
|
||||
public ModifyListenMode getModifyListenMode() {
|
||||
return modifyListenMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode for listening to changes to the List Set or Map.
|
||||
*/
|
||||
public void setModifyListenMode(ModifyListenMode modifyListenMode) {
|
||||
this.modifyListenMode = modifyListenMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a unidirectional relationship.
|
||||
*/
|
||||
public boolean isUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a unidirectional relationship.
|
||||
*/
|
||||
public void setUnidirectional(boolean unidirectional) {
|
||||
this.unidirectional = unidirectional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable version of the intersection join.
|
||||
*/
|
||||
public TableJoin createIntersectionTableJoin() {
|
||||
if (intersectionJoin != null){
|
||||
return new TableJoin(intersectionJoin, null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable version of the inverse join.
|
||||
*/
|
||||
public TableJoin createInverseTableJoin() {
|
||||
if (inverseJoin != null){
|
||||
return new TableJoin(inverseJoin, null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
public DeployTableJoin getIntersectionJoin() {
|
||||
return intersectionJoin;
|
||||
}
|
||||
|
||||
public DeployTableJoin getInverseJoin() {
|
||||
return inverseJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
public void setIntersectionJoin(DeployTableJoin intersectionJoin) {
|
||||
this.intersectionJoin = intersectionJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from foreign table to intersection table.
|
||||
*/
|
||||
public void setInverseJoin(DeployTableJoin inverseJoin) {
|
||||
this.inverseJoin = inverseJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the order by clause used to order the fetching of the data for
|
||||
* this list, set or map.
|
||||
*/
|
||||
public String getFetchOrderBy() {
|
||||
return fetchOrderBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default mapKey when returning a Map.
|
||||
*/
|
||||
public String getMapKey() {
|
||||
return mapKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default mapKey to use when returning a Map.
|
||||
*/
|
||||
public void setMapKey(String mapKey) {
|
||||
if (mapKey != null && mapKey.length() > 0) {
|
||||
this.mapKey = mapKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order by clause used to order the fetching or the data for this
|
||||
* list, set or map.
|
||||
*/
|
||||
public void setFetchOrderBy(String orderBy) {
|
||||
if (orderBy != null && orderBy.length() > 0) {
|
||||
fetchOrderBy = orderBy;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
/**
|
||||
* Property mapped to a List Set or Map.
|
||||
*/
|
||||
public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
|
||||
|
||||
ModifyListenMode modifyListenMode = ModifyListenMode.NONE;
|
||||
|
||||
/**
|
||||
* Flag to indicate manyToMany relationship.
|
||||
*/
|
||||
boolean manyToMany;
|
||||
|
||||
/**
|
||||
* Flag to indicate this is a unidirectional relationship.
|
||||
*/
|
||||
boolean unidirectional;
|
||||
|
||||
/**
|
||||
* Join for manyToMany intersection table.
|
||||
*/
|
||||
DeployTableJoin intersectionJoin;
|
||||
|
||||
/**
|
||||
* For ManyToMany this is the Inverse join used to build reference queries.
|
||||
*/
|
||||
DeployTableJoin inverseJoin;
|
||||
|
||||
String fetchOrderBy;
|
||||
|
||||
String mapKey;
|
||||
|
||||
/**
|
||||
* The type of the many, set, list or map.
|
||||
*/
|
||||
ManyType manyType;
|
||||
|
||||
/**
|
||||
* Create this property.
|
||||
*/
|
||||
public DeployBeanPropertyAssocMany(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
|
||||
super(desc, targetType);
|
||||
this.manyType = manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* When generics is not used for manyType you can specify via annotations.
|
||||
* <p>
|
||||
* Really only expect this for Scala due to a Scala compiler bug at the moment.
|
||||
* Otherwise I'd probably not bother support this.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetType(Class<?> cls){
|
||||
this.targetType = (Class<T>)cls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the many type.
|
||||
*/
|
||||
public ManyType getManyType() {
|
||||
return manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is many to many.
|
||||
*/
|
||||
public boolean isManyToMany() {
|
||||
return manyToMany;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a many to many.
|
||||
*/
|
||||
public void setManyToMany(boolean isManyToMany) {
|
||||
this.manyToMany = isManyToMany;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mode for listening to changes to the List Set or Map.
|
||||
*/
|
||||
public ModifyListenMode getModifyListenMode() {
|
||||
return modifyListenMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode for listening to changes to the List Set or Map.
|
||||
*/
|
||||
public void setModifyListenMode(ModifyListenMode modifyListenMode) {
|
||||
this.modifyListenMode = modifyListenMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a unidirectional relationship.
|
||||
*/
|
||||
public boolean isUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a unidirectional relationship.
|
||||
*/
|
||||
public void setUnidirectional(boolean unidirectional) {
|
||||
this.unidirectional = unidirectional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable version of the intersection join.
|
||||
*/
|
||||
public TableJoin createIntersectionTableJoin() {
|
||||
if (intersectionJoin != null){
|
||||
return new TableJoin(intersectionJoin, null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable version of the inverse join.
|
||||
*/
|
||||
public TableJoin createInverseTableJoin() {
|
||||
if (inverseJoin != null){
|
||||
return new TableJoin(inverseJoin, null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
public DeployTableJoin getIntersectionJoin() {
|
||||
return intersectionJoin;
|
||||
}
|
||||
|
||||
public DeployTableJoin getInverseJoin() {
|
||||
return inverseJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
public void setIntersectionJoin(DeployTableJoin intersectionJoin) {
|
||||
this.intersectionJoin = intersectionJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from foreign table to intersection table.
|
||||
*/
|
||||
public void setInverseJoin(DeployTableJoin inverseJoin) {
|
||||
this.inverseJoin = inverseJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the order by clause used to order the fetching of the data for
|
||||
* this list, set or map.
|
||||
*/
|
||||
public String getFetchOrderBy() {
|
||||
return fetchOrderBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default mapKey when returning a Map.
|
||||
*/
|
||||
public String getMapKey() {
|
||||
return mapKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default mapKey to use when returning a Map.
|
||||
*/
|
||||
public void setMapKey(String mapKey) {
|
||||
if (mapKey != null && mapKey.length() > 0) {
|
||||
this.mapKey = mapKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order by clause used to order the fetching or the data for this
|
||||
* list, set or map.
|
||||
*/
|
||||
public void setFetchOrderBy(String orderBy) {
|
||||
if (orderBy != null && orderBy.length() > 0) {
|
||||
fetchOrderBy = orderBy;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+95
-95
@@ -1,95 +1,95 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
|
||||
|
||||
/**
|
||||
* Property mapped to a joined bean.
|
||||
*/
|
||||
public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
|
||||
|
||||
boolean oneToOne;
|
||||
|
||||
boolean oneToOneExported;
|
||||
|
||||
boolean importedPrimaryKey;
|
||||
|
||||
DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public DeployBeanPropertyAssocOne(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the deploy information specifically for the deployment
|
||||
* of Embedded beans.
|
||||
*/
|
||||
public DeployBeanEmbedded getDeployEmbedded() {
|
||||
// deployment should be single threaded
|
||||
if (deployEmbedded == null){
|
||||
deployEmbedded = new DeployBeanEmbedded();
|
||||
}
|
||||
return deployEmbedded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDbColumn() {
|
||||
DeployTableJoinColumn[] columns = tableJoin.columns();
|
||||
if (columns.length == 1){
|
||||
return columns[0].getLocalDbColumn();
|
||||
}
|
||||
return super.getDbColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElPlaceHolder(EntityType et) {
|
||||
return super.getElPlaceHolder(et);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this a OneToOne property. Otherwise assumed ManyToOne.
|
||||
*/
|
||||
public boolean isOneToOne() {
|
||||
return oneToOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a OneToOne.
|
||||
*/
|
||||
public void setOneToOne(boolean oneToOne) {
|
||||
this.oneToOne = oneToOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the exported side of a OneToOne.
|
||||
*/
|
||||
public boolean isOneToOneExported() {
|
||||
return oneToOneExported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is the exported side of a OneToOne. This means
|
||||
* it doesn't 'own' the foreign key column. A OneToMany without the many.
|
||||
*/
|
||||
public void setOneToOneExported(boolean oneToOneExported) {
|
||||
this.oneToOneExported = oneToOneExported;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true this bean maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the bean maps to the primary key.
|
||||
*/
|
||||
public void setImportedPrimaryKey(boolean importedPrimaryKey) {
|
||||
this.importedPrimaryKey = importedPrimaryKey;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
|
||||
|
||||
/**
|
||||
* Property mapped to a joined bean.
|
||||
*/
|
||||
public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
|
||||
|
||||
boolean oneToOne;
|
||||
|
||||
boolean oneToOneExported;
|
||||
|
||||
boolean importedPrimaryKey;
|
||||
|
||||
DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public DeployBeanPropertyAssocOne(DeployBeanDescriptor<?> desc, Class<T> targetType) {
|
||||
super(desc, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the deploy information specifically for the deployment
|
||||
* of Embedded beans.
|
||||
*/
|
||||
public DeployBeanEmbedded getDeployEmbedded() {
|
||||
// deployment should be single threaded
|
||||
if (deployEmbedded == null){
|
||||
deployEmbedded = new DeployBeanEmbedded();
|
||||
}
|
||||
return deployEmbedded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDbColumn() {
|
||||
DeployTableJoinColumn[] columns = tableJoin.columns();
|
||||
if (columns.length == 1){
|
||||
return columns[0].getLocalDbColumn();
|
||||
}
|
||||
return super.getDbColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElPlaceHolder(EntityType et) {
|
||||
return super.getElPlaceHolder(et);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this a OneToOne property. Otherwise assumed ManyToOne.
|
||||
*/
|
||||
public boolean isOneToOne() {
|
||||
return oneToOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is a OneToOne.
|
||||
*/
|
||||
public void setOneToOne(boolean oneToOne) {
|
||||
this.oneToOne = oneToOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the exported side of a OneToOne.
|
||||
*/
|
||||
public boolean isOneToOneExported() {
|
||||
return oneToOneExported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is the exported side of a OneToOne. This means
|
||||
* it doesn't 'own' the foreign key column. A OneToMany without the many.
|
||||
*/
|
||||
public void setOneToOneExported(boolean oneToOneExported) {
|
||||
this.oneToOneExported = oneToOneExported;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true this bean maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the bean maps to the primary key.
|
||||
*/
|
||||
public void setImportedPrimaryKey(boolean importedPrimaryKey) {
|
||||
this.importedPrimaryKey = importedPrimaryKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+119
-119
@@ -1,119 +1,119 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundRoot;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundScalar;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundTypeScalarList;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
|
||||
/**
|
||||
* Property mapped to a joined bean.
|
||||
*/
|
||||
public class DeployBeanPropertyCompound extends DeployBeanProperty {
|
||||
|
||||
final CtCompoundType<?> compoundType;
|
||||
|
||||
final ScalarTypeConverter<?, ?> typeConverter;
|
||||
|
||||
DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public DeployBeanPropertyCompound(DeployBeanDescriptor<?> desc, Class<?> targetType,
|
||||
CtCompoundType<?> compoundType, ScalarTypeConverter<?, ?> typeConverter) {
|
||||
|
||||
super(desc, targetType, null, null);
|
||||
this.compoundType = compoundType;
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
public BeanPropertyCompoundRoot getFlatProperties(BeanDescriptorMap owner, BeanDescriptor<?> descriptor) {
|
||||
|
||||
// get a 'flat' list of all the scalar types, their relative property names
|
||||
// and also set their matching dbColumn
|
||||
|
||||
// represents the root property
|
||||
BeanPropertyCompoundRoot rootProperty = new BeanPropertyCompoundRoot(this);
|
||||
|
||||
// Walk the tree of a compound type collecting the
|
||||
// scalar types and non-scalar properties
|
||||
CtCompoundTypeScalarList ctMeta = new CtCompoundTypeScalarList();
|
||||
|
||||
compoundType.accumulateScalarTypes(null, ctMeta);
|
||||
|
||||
List<BeanProperty> beanPropertyList = new ArrayList<BeanProperty>();
|
||||
|
||||
|
||||
// for each of the scalar types inside a compound value object
|
||||
// build a BeanPropertyCompoundScalar with appropriate deployment
|
||||
// information.
|
||||
|
||||
for (Entry<String, ScalarType<?>> entry : ctMeta.entries()) {
|
||||
|
||||
String relativePropertyName = entry.getKey();
|
||||
ScalarType<?> scalarType = entry.getValue();
|
||||
|
||||
CtCompoundProperty ctProp = ctMeta.getCompoundType(relativePropertyName);
|
||||
|
||||
|
||||
String dbColumn = (getName() + "." + relativePropertyName).replace(".", "_");
|
||||
dbColumn = getDbColumn(relativePropertyName, dbColumn);
|
||||
|
||||
DeployBeanProperty deploy = new DeployBeanProperty(null, scalarType.getType(), scalarType, null);
|
||||
deploy.setScalarType(scalarType);
|
||||
deploy.setDbColumn(dbColumn);
|
||||
deploy.setName(relativePropertyName);
|
||||
deploy.setDbInsertable(true);
|
||||
deploy.setDbUpdateable(true);
|
||||
deploy.setDbRead(true);
|
||||
|
||||
BeanPropertyCompoundScalar bp = new BeanPropertyCompoundScalar(rootProperty, deploy, ctProp, typeConverter);
|
||||
beanPropertyList.add(bp);
|
||||
|
||||
rootProperty.register(bp);
|
||||
}
|
||||
|
||||
rootProperty.setNonScalarProperties(ctMeta.getNonScalarProperties());
|
||||
return rootProperty;
|
||||
}
|
||||
|
||||
private String getDbColumn(String propName, String defaultDbColumn) {
|
||||
if (deployEmbedded == null) {
|
||||
return defaultDbColumn;
|
||||
}
|
||||
String dbColumn = deployEmbedded.getPropertyColumnMap().get(propName);
|
||||
return dbColumn == null ? defaultDbColumn : dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the deploy information specifically for the deployment
|
||||
* of Embedded beans.
|
||||
*/
|
||||
public DeployBeanEmbedded getDeployEmbedded() {
|
||||
// deployment should be single threaded
|
||||
if (deployEmbedded == null) {
|
||||
deployEmbedded = new DeployBeanEmbedded();
|
||||
}
|
||||
return deployEmbedded;
|
||||
}
|
||||
|
||||
public ScalarTypeConverter<?, ?> getTypeConverter() {
|
||||
return typeConverter;
|
||||
}
|
||||
|
||||
public CtCompoundType<?> getCompoundType() {
|
||||
return compoundType;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundRoot;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundScalar;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundTypeScalarList;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
|
||||
/**
|
||||
* Property mapped to a joined bean.
|
||||
*/
|
||||
public class DeployBeanPropertyCompound extends DeployBeanProperty {
|
||||
|
||||
final CtCompoundType<?> compoundType;
|
||||
|
||||
final ScalarTypeConverter<?, ?> typeConverter;
|
||||
|
||||
DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public DeployBeanPropertyCompound(DeployBeanDescriptor<?> desc, Class<?> targetType,
|
||||
CtCompoundType<?> compoundType, ScalarTypeConverter<?, ?> typeConverter) {
|
||||
|
||||
super(desc, targetType, null, null);
|
||||
this.compoundType = compoundType;
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
public BeanPropertyCompoundRoot getFlatProperties(BeanDescriptorMap owner, BeanDescriptor<?> descriptor) {
|
||||
|
||||
// get a 'flat' list of all the scalar types, their relative property names
|
||||
// and also set their matching dbColumn
|
||||
|
||||
// represents the root property
|
||||
BeanPropertyCompoundRoot rootProperty = new BeanPropertyCompoundRoot(this);
|
||||
|
||||
// Walk the tree of a compound type collecting the
|
||||
// scalar types and non-scalar properties
|
||||
CtCompoundTypeScalarList ctMeta = new CtCompoundTypeScalarList();
|
||||
|
||||
compoundType.accumulateScalarTypes(null, ctMeta);
|
||||
|
||||
List<BeanProperty> beanPropertyList = new ArrayList<BeanProperty>();
|
||||
|
||||
|
||||
// for each of the scalar types inside a compound value object
|
||||
// build a BeanPropertyCompoundScalar with appropriate deployment
|
||||
// information.
|
||||
|
||||
for (Entry<String, ScalarType<?>> entry : ctMeta.entries()) {
|
||||
|
||||
String relativePropertyName = entry.getKey();
|
||||
ScalarType<?> scalarType = entry.getValue();
|
||||
|
||||
CtCompoundProperty ctProp = ctMeta.getCompoundType(relativePropertyName);
|
||||
|
||||
|
||||
String dbColumn = (getName() + "." + relativePropertyName).replace(".", "_");
|
||||
dbColumn = getDbColumn(relativePropertyName, dbColumn);
|
||||
|
||||
DeployBeanProperty deploy = new DeployBeanProperty(null, scalarType.getType(), scalarType, null);
|
||||
deploy.setScalarType(scalarType);
|
||||
deploy.setDbColumn(dbColumn);
|
||||
deploy.setName(relativePropertyName);
|
||||
deploy.setDbInsertable(true);
|
||||
deploy.setDbUpdateable(true);
|
||||
deploy.setDbRead(true);
|
||||
|
||||
BeanPropertyCompoundScalar bp = new BeanPropertyCompoundScalar(rootProperty, deploy, ctProp, typeConverter);
|
||||
beanPropertyList.add(bp);
|
||||
|
||||
rootProperty.register(bp);
|
||||
}
|
||||
|
||||
rootProperty.setNonScalarProperties(ctMeta.getNonScalarProperties());
|
||||
return rootProperty;
|
||||
}
|
||||
|
||||
private String getDbColumn(String propName, String defaultDbColumn) {
|
||||
if (deployEmbedded == null) {
|
||||
return defaultDbColumn;
|
||||
}
|
||||
String dbColumn = deployEmbedded.getPropertyColumnMap().get(propName);
|
||||
return dbColumn == null ? defaultDbColumn : dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the deploy information specifically for the deployment
|
||||
* of Embedded beans.
|
||||
*/
|
||||
public DeployBeanEmbedded getDeployEmbedded() {
|
||||
// deployment should be single threaded
|
||||
if (deployEmbedded == null) {
|
||||
deployEmbedded = new DeployBeanEmbedded();
|
||||
}
|
||||
return deployEmbedded;
|
||||
}
|
||||
|
||||
public ScalarTypeConverter<?, ?> getTypeConverter() {
|
||||
return typeConverter;
|
||||
}
|
||||
|
||||
public CtCompoundType<?> getCompoundType() {
|
||||
return compoundType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+387
-387
@@ -1,387 +1,387 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertySimpleCollection;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeString;
|
||||
|
||||
/**
|
||||
* Helper object to classify BeanProperties into appropriate lists.
|
||||
*/
|
||||
public class DeployBeanPropertyLists {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployBeanPropertyLists.class);
|
||||
|
||||
private BeanProperty versionProperty;
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
|
||||
private final LinkedHashMap<String, BeanProperty> propertyMap;
|
||||
|
||||
private final ArrayList<BeanProperty> ids = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> local = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> mutable = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> manys = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> nonManys = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> ones = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> onesExported = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> onesImported = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> embedded = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> baseScalar = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanPropertyCompound> baseCompound = new ArrayList<BeanPropertyCompound>();
|
||||
|
||||
private final ArrayList<BeanProperty> transients = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> nonTransients = new ArrayList<BeanProperty>();
|
||||
|
||||
private final TableJoin[] tableJoins;
|
||||
|
||||
private final BeanPropertyAssocOne<?> unidirectional;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor<?> desc, DeployBeanDescriptor<?> deploy) {
|
||||
this.desc = desc;
|
||||
|
||||
DeployBeanPropertyAssocOne<?> deployUnidirectional = deploy.getUnidirectional();
|
||||
if (deployUnidirectional == null) {
|
||||
unidirectional = null;
|
||||
} else {
|
||||
unidirectional = new BeanPropertyAssocOne(owner, desc, deployUnidirectional);
|
||||
}
|
||||
|
||||
this.propertyMap = new LinkedHashMap<String, BeanProperty>();
|
||||
|
||||
for (DeployBeanProperty prop : deploy.propertiesAll()) {
|
||||
BeanProperty beanProp = createBeanProperty(owner, prop);
|
||||
propertyMap.put(beanProp.getName(), beanProp);
|
||||
}
|
||||
|
||||
int order = 0;
|
||||
for (BeanProperty prop : propertyMap.values()) {
|
||||
prop.setDeployOrder(order++);
|
||||
allocateToList(prop);
|
||||
}
|
||||
|
||||
InheritInfo inheritInfo = deploy.getInheritInfo();
|
||||
if (inheritInfo != null) {
|
||||
// Create a BeanProperty for the discriminator column to support
|
||||
// using RawSql queries with inheritance
|
||||
String discriminatorColumn = inheritInfo.getDiscriminatorColumn();
|
||||
DeployBeanProperty discDeployProp = new DeployBeanProperty(deploy, String.class, new ScalarTypeString(), null);
|
||||
discDeployProp.setDiscriminator(true);
|
||||
discDeployProp.setName(discriminatorColumn);
|
||||
discDeployProp.setDbColumn(discriminatorColumn);
|
||||
|
||||
// create the discriminator BeanProperty and only register it in the propertyMap
|
||||
BeanProperty dprop = new BeanProperty(owner, desc, discDeployProp);
|
||||
propertyMap.put(dprop.getName(), dprop);
|
||||
}
|
||||
|
||||
List<DeployTableJoin> deployTableJoins = deploy.getTableJoins();
|
||||
tableJoins = new TableJoin[deployTableJoins.size()];
|
||||
for (int i = 0; i < deployTableJoins.size(); i++) {
|
||||
tableJoins[i] = new TableJoin(deployTableJoins.get(i), propertyMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unidirectional.
|
||||
*/
|
||||
public BeanPropertyAssocOne<?> getUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate the property to a list.
|
||||
*/
|
||||
private void allocateToList(BeanProperty prop) {
|
||||
if (prop.isTransient()) {
|
||||
transients.add(prop);
|
||||
return;
|
||||
}
|
||||
if (prop.isId()) {
|
||||
ids.add(prop);
|
||||
return;
|
||||
} else {
|
||||
nonTransients.add(prop);
|
||||
}
|
||||
|
||||
if (prop.isMutableScalarType()) {
|
||||
mutable.add(prop);
|
||||
}
|
||||
|
||||
if (desc.getInheritInfo() != null && prop.isLocal()) {
|
||||
local.add(prop);
|
||||
}
|
||||
|
||||
if (prop instanceof BeanPropertyAssocMany<?>) {
|
||||
manys.add(prop);
|
||||
|
||||
} else {
|
||||
nonManys.add(prop);
|
||||
if (prop instanceof BeanPropertyAssocOne<?>) {
|
||||
if (prop.isEmbedded()) {
|
||||
embedded.add(prop);
|
||||
} else {
|
||||
ones.add(prop);
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>) prop;
|
||||
if (assocOne.isOneToOneExported()) {
|
||||
onesExported.add(prop);
|
||||
} else {
|
||||
onesImported.add(prop);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// its a "base" property...
|
||||
if (prop.isVersion()) {
|
||||
if (versionProperty == null) {
|
||||
versionProperty = prop;
|
||||
} else {
|
||||
logger.warn("Multiple @Version properties - property " + prop.getFullBeanName()
|
||||
+ " not treated as a version property");
|
||||
}
|
||||
}
|
||||
if (prop instanceof BeanPropertyCompound) {
|
||||
baseCompound.add((BeanPropertyCompound) prop);
|
||||
} else {
|
||||
baseScalar.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedHashMap<String, BeanProperty> getPropertyMap() {
|
||||
return propertyMap;
|
||||
}
|
||||
|
||||
public TableJoin[] getTableJoin() {
|
||||
return tableJoins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base scalar properties (excludes Id and secondary table
|
||||
* properties).
|
||||
*/
|
||||
public BeanProperty[] getBaseScalar() {
|
||||
return (BeanProperty[]) baseScalar.toArray(new BeanProperty[baseScalar.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyCompound[] getBaseCompound() {
|
||||
return (BeanPropertyCompound[]) baseCompound.toArray(new BeanPropertyCompound[baseCompound.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty getId() {
|
||||
if (ids.size() > 1) {
|
||||
String msg = "Issue with bean "+desc+". Ebean does not support multiple @Id properties. You need to convert to using an @EmbeddedId."
|
||||
+" Please email the ebean google group if you need further clarification.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (ids.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return ids.get(0);
|
||||
}
|
||||
|
||||
public BeanProperty[] getNonTransients() {
|
||||
return (BeanProperty[]) nonTransients.toArray(new BeanProperty[nonTransients.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty[] getTransients() {
|
||||
return (BeanProperty[]) transients.toArray(new BeanProperty[transients.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
public BeanProperty[] getLocal() {
|
||||
return (BeanProperty[]) local.toArray(new BeanProperty[local.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty[] getMutable() {
|
||||
return (BeanProperty[]) mutable.toArray(new BeanProperty[mutable.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getEmbedded() {
|
||||
return (BeanPropertyAssocOne[]) embedded.toArray(new BeanPropertyAssocOne[embedded.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneExported() {
|
||||
return (BeanPropertyAssocOne[]) onesExported.toArray(new BeanPropertyAssocOne[onesExported.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneImported() {
|
||||
return (BeanPropertyAssocOne[]) onesImported.toArray(new BeanPropertyAssocOne[onesImported.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOnes() {
|
||||
return (BeanPropertyAssocOne[]) ones.toArray(new BeanPropertyAssocOne[ones.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneExportedSave() {
|
||||
return getOne(false, Mode.Save);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneExportedDelete() {
|
||||
return getOne(false, Mode.Delete);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneImportedSave() {
|
||||
return getOne(true, Mode.Save);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneImportedDelete() {
|
||||
return getOne(true, Mode.Delete);
|
||||
}
|
||||
|
||||
public BeanProperty[] getNonMany() {
|
||||
return (BeanProperty[]) nonManys.toArray(new BeanProperty[nonManys.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getMany() {
|
||||
return (BeanPropertyAssocMany[]) manys.toArray(new BeanPropertyAssocMany[manys.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getManySave() {
|
||||
return getMany(Mode.Save);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getManyDelete() {
|
||||
return getMany(Mode.Delete);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getManyToMany() {
|
||||
return getMany2Many();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mode used to determine which BeanPropertyAssoc to include.
|
||||
*/
|
||||
private enum Mode {
|
||||
Save, Delete, Validate;
|
||||
}
|
||||
|
||||
private BeanPropertyAssocOne<?>[] getOne(boolean imported, Mode mode) {
|
||||
ArrayList<BeanPropertyAssocOne<?>> list = new ArrayList<BeanPropertyAssocOne<?>>();
|
||||
for (int i = 0; i < ones.size(); i++) {
|
||||
BeanPropertyAssocOne<?> prop = (BeanPropertyAssocOne<?>) ones.get(i);
|
||||
if (imported != prop.isOneToOneExported()) {
|
||||
switch (mode) {
|
||||
case Save:
|
||||
if (prop.getCascadeInfo().isSave()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Delete:
|
||||
if (prop.getCascadeInfo().isDelete()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Validate:
|
||||
if (prop.getCascadeInfo().isValidate()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (BeanPropertyAssocOne[]) list.toArray(new BeanPropertyAssocOne[list.size()]);
|
||||
}
|
||||
|
||||
private BeanPropertyAssocMany<?>[] getMany2Many() {
|
||||
ArrayList<BeanPropertyAssocMany<?>> list = new ArrayList<BeanPropertyAssocMany<?>>();
|
||||
for (int i = 0; i < manys.size(); i++) {
|
||||
BeanPropertyAssocMany<?> prop = (BeanPropertyAssocMany<?>) manys.get(i);
|
||||
if (prop.isManyToMany()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
|
||||
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
|
||||
}
|
||||
|
||||
private BeanPropertyAssocMany<?>[] getMany(Mode mode) {
|
||||
ArrayList<BeanPropertyAssocMany<?>> list = new ArrayList<BeanPropertyAssocMany<?>>();
|
||||
for (int i = 0; i < manys.size(); i++) {
|
||||
BeanPropertyAssocMany<?> prop = (BeanPropertyAssocMany<?>) manys.get(i);
|
||||
|
||||
switch (mode) {
|
||||
case Save:
|
||||
if (prop.getCascadeInfo().isSave() || prop.isManyToMany()
|
||||
|| ModifyListenMode.REMOVALS.equals(prop.getModifyListenMode())) {
|
||||
// Note ManyToMany always included as we always 'save'
|
||||
// the relationship via insert/delete of intersection table
|
||||
// REMOVALS means including PrivateOwned relationships
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Delete:
|
||||
if (prop.getCascadeInfo().isDelete() || ModifyListenMode.REMOVALS.equals(prop.getModifyListenMode())) {
|
||||
// REMOVALS means including PrivateOwned relationships
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Validate:
|
||||
if (prop.getCascadeInfo().isValidate()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private BeanProperty createBeanProperty(BeanDescriptorMap owner, DeployBeanProperty deployProp) {
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertyAssocOne) {
|
||||
return new BeanPropertyAssocOne(owner, desc, (DeployBeanPropertyAssocOne) deployProp);
|
||||
}
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertySimpleCollection<?>) {
|
||||
return new BeanPropertySimpleCollection(owner, desc, (DeployBeanPropertySimpleCollection) deployProp);
|
||||
}
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertyAssocMany) {
|
||||
return new BeanPropertyAssocMany(owner, desc, (DeployBeanPropertyAssocMany) deployProp);
|
||||
}
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertyCompound) {
|
||||
return new BeanPropertyCompound(owner, desc, (DeployBeanPropertyCompound) deployProp);
|
||||
}
|
||||
|
||||
return new BeanProperty(owner, desc, deployProp);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertySimpleCollection;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeString;
|
||||
|
||||
/**
|
||||
* Helper object to classify BeanProperties into appropriate lists.
|
||||
*/
|
||||
public class DeployBeanPropertyLists {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployBeanPropertyLists.class);
|
||||
|
||||
private BeanProperty versionProperty;
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
|
||||
private final LinkedHashMap<String, BeanProperty> propertyMap;
|
||||
|
||||
private final ArrayList<BeanProperty> ids = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> local = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> mutable = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> manys = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> nonManys = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> ones = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> onesExported = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> onesImported = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> embedded = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> baseScalar = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanPropertyCompound> baseCompound = new ArrayList<BeanPropertyCompound>();
|
||||
|
||||
private final ArrayList<BeanProperty> transients = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> nonTransients = new ArrayList<BeanProperty>();
|
||||
|
||||
private final TableJoin[] tableJoins;
|
||||
|
||||
private final BeanPropertyAssocOne<?> unidirectional;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor<?> desc, DeployBeanDescriptor<?> deploy) {
|
||||
this.desc = desc;
|
||||
|
||||
DeployBeanPropertyAssocOne<?> deployUnidirectional = deploy.getUnidirectional();
|
||||
if (deployUnidirectional == null) {
|
||||
unidirectional = null;
|
||||
} else {
|
||||
unidirectional = new BeanPropertyAssocOne(owner, desc, deployUnidirectional);
|
||||
}
|
||||
|
||||
this.propertyMap = new LinkedHashMap<String, BeanProperty>();
|
||||
|
||||
for (DeployBeanProperty prop : deploy.propertiesAll()) {
|
||||
BeanProperty beanProp = createBeanProperty(owner, prop);
|
||||
propertyMap.put(beanProp.getName(), beanProp);
|
||||
}
|
||||
|
||||
int order = 0;
|
||||
for (BeanProperty prop : propertyMap.values()) {
|
||||
prop.setDeployOrder(order++);
|
||||
allocateToList(prop);
|
||||
}
|
||||
|
||||
InheritInfo inheritInfo = deploy.getInheritInfo();
|
||||
if (inheritInfo != null) {
|
||||
// Create a BeanProperty for the discriminator column to support
|
||||
// using RawSql queries with inheritance
|
||||
String discriminatorColumn = inheritInfo.getDiscriminatorColumn();
|
||||
DeployBeanProperty discDeployProp = new DeployBeanProperty(deploy, String.class, new ScalarTypeString(), null);
|
||||
discDeployProp.setDiscriminator(true);
|
||||
discDeployProp.setName(discriminatorColumn);
|
||||
discDeployProp.setDbColumn(discriminatorColumn);
|
||||
|
||||
// create the discriminator BeanProperty and only register it in the propertyMap
|
||||
BeanProperty dprop = new BeanProperty(owner, desc, discDeployProp);
|
||||
propertyMap.put(dprop.getName(), dprop);
|
||||
}
|
||||
|
||||
List<DeployTableJoin> deployTableJoins = deploy.getTableJoins();
|
||||
tableJoins = new TableJoin[deployTableJoins.size()];
|
||||
for (int i = 0; i < deployTableJoins.size(); i++) {
|
||||
tableJoins[i] = new TableJoin(deployTableJoins.get(i), propertyMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unidirectional.
|
||||
*/
|
||||
public BeanPropertyAssocOne<?> getUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate the property to a list.
|
||||
*/
|
||||
private void allocateToList(BeanProperty prop) {
|
||||
if (prop.isTransient()) {
|
||||
transients.add(prop);
|
||||
return;
|
||||
}
|
||||
if (prop.isId()) {
|
||||
ids.add(prop);
|
||||
return;
|
||||
} else {
|
||||
nonTransients.add(prop);
|
||||
}
|
||||
|
||||
if (prop.isMutableScalarType()) {
|
||||
mutable.add(prop);
|
||||
}
|
||||
|
||||
if (desc.getInheritInfo() != null && prop.isLocal()) {
|
||||
local.add(prop);
|
||||
}
|
||||
|
||||
if (prop instanceof BeanPropertyAssocMany<?>) {
|
||||
manys.add(prop);
|
||||
|
||||
} else {
|
||||
nonManys.add(prop);
|
||||
if (prop instanceof BeanPropertyAssocOne<?>) {
|
||||
if (prop.isEmbedded()) {
|
||||
embedded.add(prop);
|
||||
} else {
|
||||
ones.add(prop);
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>) prop;
|
||||
if (assocOne.isOneToOneExported()) {
|
||||
onesExported.add(prop);
|
||||
} else {
|
||||
onesImported.add(prop);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// its a "base" property...
|
||||
if (prop.isVersion()) {
|
||||
if (versionProperty == null) {
|
||||
versionProperty = prop;
|
||||
} else {
|
||||
logger.warn("Multiple @Version properties - property " + prop.getFullBeanName()
|
||||
+ " not treated as a version property");
|
||||
}
|
||||
}
|
||||
if (prop instanceof BeanPropertyCompound) {
|
||||
baseCompound.add((BeanPropertyCompound) prop);
|
||||
} else {
|
||||
baseScalar.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedHashMap<String, BeanProperty> getPropertyMap() {
|
||||
return propertyMap;
|
||||
}
|
||||
|
||||
public TableJoin[] getTableJoin() {
|
||||
return tableJoins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base scalar properties (excludes Id and secondary table
|
||||
* properties).
|
||||
*/
|
||||
public BeanProperty[] getBaseScalar() {
|
||||
return (BeanProperty[]) baseScalar.toArray(new BeanProperty[baseScalar.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyCompound[] getBaseCompound() {
|
||||
return (BeanPropertyCompound[]) baseCompound.toArray(new BeanPropertyCompound[baseCompound.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty getId() {
|
||||
if (ids.size() > 1) {
|
||||
String msg = "Issue with bean "+desc+". Ebean does not support multiple @Id properties. You need to convert to using an @EmbeddedId."
|
||||
+" Please email the ebean google group if you need further clarification.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (ids.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return ids.get(0);
|
||||
}
|
||||
|
||||
public BeanProperty[] getNonTransients() {
|
||||
return (BeanProperty[]) nonTransients.toArray(new BeanProperty[nonTransients.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty[] getTransients() {
|
||||
return (BeanProperty[]) transients.toArray(new BeanProperty[transients.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty getVersionProperty() {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
public BeanProperty[] getLocal() {
|
||||
return (BeanProperty[]) local.toArray(new BeanProperty[local.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty[] getMutable() {
|
||||
return (BeanProperty[]) mutable.toArray(new BeanProperty[mutable.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getEmbedded() {
|
||||
return (BeanPropertyAssocOne[]) embedded.toArray(new BeanPropertyAssocOne[embedded.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneExported() {
|
||||
return (BeanPropertyAssocOne[]) onesExported.toArray(new BeanPropertyAssocOne[onesExported.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneImported() {
|
||||
return (BeanPropertyAssocOne[]) onesImported.toArray(new BeanPropertyAssocOne[onesImported.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOnes() {
|
||||
return (BeanPropertyAssocOne[]) ones.toArray(new BeanPropertyAssocOne[ones.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneExportedSave() {
|
||||
return getOne(false, Mode.Save);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneExportedDelete() {
|
||||
return getOne(false, Mode.Delete);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneImportedSave() {
|
||||
return getOne(true, Mode.Save);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocOne<?>[] getOneImportedDelete() {
|
||||
return getOne(true, Mode.Delete);
|
||||
}
|
||||
|
||||
public BeanProperty[] getNonMany() {
|
||||
return (BeanProperty[]) nonManys.toArray(new BeanProperty[nonManys.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getMany() {
|
||||
return (BeanPropertyAssocMany[]) manys.toArray(new BeanPropertyAssocMany[manys.size()]);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getManySave() {
|
||||
return getMany(Mode.Save);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getManyDelete() {
|
||||
return getMany(Mode.Delete);
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?>[] getManyToMany() {
|
||||
return getMany2Many();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mode used to determine which BeanPropertyAssoc to include.
|
||||
*/
|
||||
private enum Mode {
|
||||
Save, Delete, Validate;
|
||||
}
|
||||
|
||||
private BeanPropertyAssocOne<?>[] getOne(boolean imported, Mode mode) {
|
||||
ArrayList<BeanPropertyAssocOne<?>> list = new ArrayList<BeanPropertyAssocOne<?>>();
|
||||
for (int i = 0; i < ones.size(); i++) {
|
||||
BeanPropertyAssocOne<?> prop = (BeanPropertyAssocOne<?>) ones.get(i);
|
||||
if (imported != prop.isOneToOneExported()) {
|
||||
switch (mode) {
|
||||
case Save:
|
||||
if (prop.getCascadeInfo().isSave()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Delete:
|
||||
if (prop.getCascadeInfo().isDelete()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Validate:
|
||||
if (prop.getCascadeInfo().isValidate()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (BeanPropertyAssocOne[]) list.toArray(new BeanPropertyAssocOne[list.size()]);
|
||||
}
|
||||
|
||||
private BeanPropertyAssocMany<?>[] getMany2Many() {
|
||||
ArrayList<BeanPropertyAssocMany<?>> list = new ArrayList<BeanPropertyAssocMany<?>>();
|
||||
for (int i = 0; i < manys.size(); i++) {
|
||||
BeanPropertyAssocMany<?> prop = (BeanPropertyAssocMany<?>) manys.get(i);
|
||||
if (prop.isManyToMany()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
|
||||
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
|
||||
}
|
||||
|
||||
private BeanPropertyAssocMany<?>[] getMany(Mode mode) {
|
||||
ArrayList<BeanPropertyAssocMany<?>> list = new ArrayList<BeanPropertyAssocMany<?>>();
|
||||
for (int i = 0; i < manys.size(); i++) {
|
||||
BeanPropertyAssocMany<?> prop = (BeanPropertyAssocMany<?>) manys.get(i);
|
||||
|
||||
switch (mode) {
|
||||
case Save:
|
||||
if (prop.getCascadeInfo().isSave() || prop.isManyToMany()
|
||||
|| ModifyListenMode.REMOVALS.equals(prop.getModifyListenMode())) {
|
||||
// Note ManyToMany always included as we always 'save'
|
||||
// the relationship via insert/delete of intersection table
|
||||
// REMOVALS means including PrivateOwned relationships
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Delete:
|
||||
if (prop.getCascadeInfo().isDelete() || ModifyListenMode.REMOVALS.equals(prop.getModifyListenMode())) {
|
||||
// REMOVALS means including PrivateOwned relationships
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
case Validate:
|
||||
if (prop.getCascadeInfo().isValidate()) {
|
||||
list.add(prop);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private BeanProperty createBeanProperty(BeanDescriptorMap owner, DeployBeanProperty deployProp) {
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertyAssocOne) {
|
||||
return new BeanPropertyAssocOne(owner, desc, (DeployBeanPropertyAssocOne) deployProp);
|
||||
}
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertySimpleCollection<?>) {
|
||||
return new BeanPropertySimpleCollection(owner, desc, (DeployBeanPropertySimpleCollection) deployProp);
|
||||
}
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertyAssocMany) {
|
||||
return new BeanPropertyAssocMany(owner, desc, (DeployBeanPropertyAssocMany) deployProp);
|
||||
}
|
||||
|
||||
if (deployProp instanceof DeployBeanPropertyCompound) {
|
||||
return new BeanPropertyCompound(owner, desc, (DeployBeanPropertyCompound) deployProp);
|
||||
}
|
||||
|
||||
return new BeanProperty(owner, desc, deployProp);
|
||||
}
|
||||
}
|
||||
|
||||
+29
-29
@@ -1,29 +1,29 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
|
||||
public class DeployBeanPropertySimpleCollection<T> extends DeployBeanPropertyAssocMany<T> {
|
||||
|
||||
public DeployBeanPropertySimpleCollection(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
|
||||
super(desc, targetType, manyType);
|
||||
this.modifyListenMode = ModifyListenMode.ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false as never a ManyToMany.
|
||||
*/
|
||||
@Override
|
||||
public boolean isManyToMany() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true as always Unidirectional.
|
||||
*/
|
||||
@Override
|
||||
public boolean isUnidirectional() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
|
||||
public class DeployBeanPropertySimpleCollection<T> extends DeployBeanPropertyAssocMany<T> {
|
||||
|
||||
public DeployBeanPropertySimpleCollection(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
|
||||
super(desc, targetType, manyType);
|
||||
this.modifyListenMode = ModifyListenMode.ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false as never a ManyToMany.
|
||||
*/
|
||||
@Override
|
||||
public boolean isManyToMany() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true as always Unidirectional.
|
||||
*/
|
||||
@Override
|
||||
public boolean isUnidirectional() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
|
||||
/**
|
||||
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
|
||||
* recursion issues due to the potentially bi-directional and circular
|
||||
* relationships between beans.
|
||||
* <p>
|
||||
* It holds the main deployment information and not all the detail that is held
|
||||
* in a BeanDescriptor.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployBeanTable {
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
/**
|
||||
* The base table.
|
||||
*/
|
||||
private String baseTable;
|
||||
|
||||
private List<DeployBeanProperty> idProperties;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
*/
|
||||
public DeployBeanTable(Class<?> beanType) {
|
||||
this.beanType = beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table for this BeanTable.
|
||||
* This is used to determine the join information
|
||||
* for associations.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base table for this BeanTable.
|
||||
*/
|
||||
public void setBaseTable(String baseTable) {
|
||||
this.baseTable = baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id properties.
|
||||
*/
|
||||
public BeanProperty[] createIdProperties(BeanDescriptorMap owner) {
|
||||
BeanProperty[] props = new BeanProperty[idProperties.size()];
|
||||
for (int i = 0; i < idProperties.size(); i++) {
|
||||
props[i] = createProperty(owner, idProperties.get(i));
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private BeanProperty createProperty(BeanDescriptorMap owner, DeployBeanProperty prop){
|
||||
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>){
|
||||
return new BeanPropertyAssocOne(owner, (DeployBeanPropertyAssocOne<?>)prop);
|
||||
|
||||
} else {
|
||||
return new BeanProperty(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Id properties.
|
||||
*/
|
||||
public void setIdProperties(List<DeployBeanProperty> idProperties) {
|
||||
this.idProperties = idProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class for this beanTable.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
|
||||
/**
|
||||
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
|
||||
* recursion issues due to the potentially bi-directional and circular
|
||||
* relationships between beans.
|
||||
* <p>
|
||||
* It holds the main deployment information and not all the detail that is held
|
||||
* in a BeanDescriptor.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployBeanTable {
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
/**
|
||||
* The base table.
|
||||
*/
|
||||
private String baseTable;
|
||||
|
||||
private List<DeployBeanProperty> idProperties;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
*/
|
||||
public DeployBeanTable(Class<?> beanType) {
|
||||
this.beanType = beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table for this BeanTable.
|
||||
* This is used to determine the join information
|
||||
* for associations.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base table for this BeanTable.
|
||||
*/
|
||||
public void setBaseTable(String baseTable) {
|
||||
this.baseTable = baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id properties.
|
||||
*/
|
||||
public BeanProperty[] createIdProperties(BeanDescriptorMap owner) {
|
||||
BeanProperty[] props = new BeanProperty[idProperties.size()];
|
||||
for (int i = 0; i < idProperties.size(); i++) {
|
||||
props[i] = createProperty(owner, idProperties.get(i));
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private BeanProperty createProperty(BeanDescriptorMap owner, DeployBeanProperty prop){
|
||||
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>){
|
||||
return new BeanPropertyAssocOne(owner, (DeployBeanPropertyAssocOne<?>)prop);
|
||||
|
||||
} else {
|
||||
return new BeanProperty(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Id properties.
|
||||
*/
|
||||
public void setIdProperties(List<DeployBeanProperty> idProperties) {
|
||||
this.idProperties = idProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class for this beanTable.
|
||||
*/
|
||||
public Class<?> getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,212 +1,212 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Represents a join to another table during deployment phase.
|
||||
* <p>
|
||||
* This gets converted into a immutable TableJoin when complete.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployTableJoin {
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for intersection tables
|
||||
* (ManyToMany).
|
||||
*/
|
||||
private boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* The joined table.
|
||||
*/
|
||||
private String table;
|
||||
|
||||
/**
|
||||
* The type of join. LEFT OUTER etc.
|
||||
*/
|
||||
private SqlJoinType type = SqlJoinType.INNER;
|
||||
|
||||
/**
|
||||
* The list of properties mapped to this joined table.
|
||||
*/
|
||||
private ArrayList<DeployBeanProperty> properties = new ArrayList<DeployBeanProperty>();
|
||||
|
||||
/**
|
||||
* The list of join column pairs. Used to generate the on clause.
|
||||
*/
|
||||
private ArrayList<DeployTableJoinColumn> columns = new ArrayList<DeployTableJoinColumn>(4);
|
||||
|
||||
/**
|
||||
* The persist cascade info.
|
||||
*/
|
||||
private BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
private InheritInfo inheritInfo;
|
||||
|
||||
/**
|
||||
* Create a DeployTableJoin.
|
||||
*/
|
||||
public DeployTableJoin() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type + " " + table + " " + columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the imported foreign key maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for intersection tables
|
||||
* (ManyToMany).
|
||||
*/
|
||||
public void setImportedPrimaryKey(boolean importedPrimaryKey) {
|
||||
this.importedPrimaryKey = importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the JoinOnPair have been set.
|
||||
*/
|
||||
public boolean hasJoinColumns() {
|
||||
return columns.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the columns to this join potentially reversing the columns.
|
||||
*/
|
||||
public void setColumns(DeployTableJoinColumn[] cols, boolean reverse) {
|
||||
columns = new ArrayList<DeployTableJoinColumn>();
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
addJoinColumn(cols[i].copy(reverse));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a join pair
|
||||
*/
|
||||
public void addJoinColumn(DeployTableJoinColumn pair) {
|
||||
columns.add(pair);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn
|
||||
* <p>
|
||||
* The order is generally true for OneToMany and false for ManyToOne relationships.
|
||||
* </p>
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
if (!"".equals(jc.table())) {
|
||||
setTable(jc.table());
|
||||
}
|
||||
if (!"".equals(jc.name()) || !"".equals(jc.referencedColumnName())) {
|
||||
// only add the join column details when name or referencedColumnName is specified
|
||||
addJoinColumn(new DeployTableJoinColumn(order, jc, beanTable));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn array.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn[] jcArray, BeanTable beanTable) {
|
||||
for (int i = 0; i < jcArray.length; i++) {
|
||||
addJoinColumn(order, jcArray[i], beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
public DeployTableJoinColumn[] columns() {
|
||||
return (DeployTableJoinColumn[]) columns.toArray(new DeployTableJoinColumn[columns.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* For secondary table joins returns the properties mapped to that table.
|
||||
*/
|
||||
public DeployBeanProperty[] properties() {
|
||||
return (DeployBeanProperty[]) properties.toArray(new DeployBeanProperty[properties.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the joined table name.
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the joined table name.
|
||||
*/
|
||||
public void setTable(String table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of join. LEFT OUTER JOIN etc.
|
||||
*/
|
||||
public SqlJoinType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this join is a left outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return type == SqlJoinType.OUTER;
|
||||
}
|
||||
|
||||
public void setType(SqlJoinType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DeployTableJoin createInverse(String tableName) {
|
||||
|
||||
DeployTableJoin inverse = new DeployTableJoin();
|
||||
return copyInternal(inverse, true, tableName, true);
|
||||
}
|
||||
|
||||
public DeployTableJoin copyTo(DeployTableJoin destJoin, boolean reverse, String tableName) {
|
||||
return copyInternal(destJoin, reverse, tableName, true);
|
||||
}
|
||||
|
||||
public DeployTableJoin copyWithoutType(DeployTableJoin destJoin, boolean reverse, String tableName) {
|
||||
return copyInternal(destJoin, reverse, tableName, false);
|
||||
}
|
||||
|
||||
private DeployTableJoin copyInternal(DeployTableJoin destJoin, boolean reverse, String tableName, boolean withType) {
|
||||
|
||||
destJoin.setTable(tableName);
|
||||
if (withType) {
|
||||
destJoin.setType(type);
|
||||
}
|
||||
destJoin.setColumns(columns(), reverse);
|
||||
|
||||
return destJoin;
|
||||
}
|
||||
|
||||
public InheritInfo getInheritInfo() {
|
||||
return inheritInfo;
|
||||
}
|
||||
|
||||
public void setInheritInfo(InheritInfo inheritInfo) {
|
||||
this.inheritInfo = inheritInfo;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Represents a join to another table during deployment phase.
|
||||
* <p>
|
||||
* This gets converted into a immutable TableJoin when complete.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployTableJoin {
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for intersection tables
|
||||
* (ManyToMany).
|
||||
*/
|
||||
private boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* The joined table.
|
||||
*/
|
||||
private String table;
|
||||
|
||||
/**
|
||||
* The type of join. LEFT OUTER etc.
|
||||
*/
|
||||
private SqlJoinType type = SqlJoinType.INNER;
|
||||
|
||||
/**
|
||||
* The list of properties mapped to this joined table.
|
||||
*/
|
||||
private ArrayList<DeployBeanProperty> properties = new ArrayList<DeployBeanProperty>();
|
||||
|
||||
/**
|
||||
* The list of join column pairs. Used to generate the on clause.
|
||||
*/
|
||||
private ArrayList<DeployTableJoinColumn> columns = new ArrayList<DeployTableJoinColumn>(4);
|
||||
|
||||
/**
|
||||
* The persist cascade info.
|
||||
*/
|
||||
private BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
private InheritInfo inheritInfo;
|
||||
|
||||
/**
|
||||
* Create a DeployTableJoin.
|
||||
*/
|
||||
public DeployTableJoin() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type + " " + table + " " + columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the imported foreign key maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for intersection tables
|
||||
* (ManyToMany).
|
||||
*/
|
||||
public void setImportedPrimaryKey(boolean importedPrimaryKey) {
|
||||
this.importedPrimaryKey = importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the JoinOnPair have been set.
|
||||
*/
|
||||
public boolean hasJoinColumns() {
|
||||
return columns.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the columns to this join potentially reversing the columns.
|
||||
*/
|
||||
public void setColumns(DeployTableJoinColumn[] cols, boolean reverse) {
|
||||
columns = new ArrayList<DeployTableJoinColumn>();
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
addJoinColumn(cols[i].copy(reverse));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a join pair
|
||||
*/
|
||||
public void addJoinColumn(DeployTableJoinColumn pair) {
|
||||
columns.add(pair);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn
|
||||
* <p>
|
||||
* The order is generally true for OneToMany and false for ManyToOne relationships.
|
||||
* </p>
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
if (!"".equals(jc.table())) {
|
||||
setTable(jc.table());
|
||||
}
|
||||
if (!"".equals(jc.name()) || !"".equals(jc.referencedColumnName())) {
|
||||
// only add the join column details when name or referencedColumnName is specified
|
||||
addJoinColumn(new DeployTableJoinColumn(order, jc, beanTable));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn array.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn[] jcArray, BeanTable beanTable) {
|
||||
for (int i = 0; i < jcArray.length; i++) {
|
||||
addJoinColumn(order, jcArray[i], beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
public DeployTableJoinColumn[] columns() {
|
||||
return (DeployTableJoinColumn[]) columns.toArray(new DeployTableJoinColumn[columns.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* For secondary table joins returns the properties mapped to that table.
|
||||
*/
|
||||
public DeployBeanProperty[] properties() {
|
||||
return (DeployBeanProperty[]) properties.toArray(new DeployBeanProperty[properties.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the joined table name.
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the joined table name.
|
||||
*/
|
||||
public void setTable(String table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of join. LEFT OUTER JOIN etc.
|
||||
*/
|
||||
public SqlJoinType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this join is a left outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return type == SqlJoinType.OUTER;
|
||||
}
|
||||
|
||||
public void setType(SqlJoinType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DeployTableJoin createInverse(String tableName) {
|
||||
|
||||
DeployTableJoin inverse = new DeployTableJoin();
|
||||
return copyInternal(inverse, true, tableName, true);
|
||||
}
|
||||
|
||||
public DeployTableJoin copyTo(DeployTableJoin destJoin, boolean reverse, String tableName) {
|
||||
return copyInternal(destJoin, reverse, tableName, true);
|
||||
}
|
||||
|
||||
public DeployTableJoin copyWithoutType(DeployTableJoin destJoin, boolean reverse, String tableName) {
|
||||
return copyInternal(destJoin, reverse, tableName, false);
|
||||
}
|
||||
|
||||
private DeployTableJoin copyInternal(DeployTableJoin destJoin, boolean reverse, String tableName, boolean withType) {
|
||||
|
||||
destJoin.setTable(tableName);
|
||||
if (withType) {
|
||||
destJoin.setType(type);
|
||||
}
|
||||
destJoin.setColumns(columns(), reverse);
|
||||
|
||||
return destJoin;
|
||||
}
|
||||
|
||||
public InheritInfo getInheritInfo() {
|
||||
return inheritInfo;
|
||||
}
|
||||
|
||||
public void setInheritInfo(InheritInfo inheritInfo) {
|
||||
this.inheritInfo = inheritInfo;
|
||||
}
|
||||
}
|
||||
|
||||
+178
-178
@@ -1,178 +1,178 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
|
||||
/**
|
||||
* A join pair of local and foreign properties.
|
||||
*/
|
||||
public class DeployTableJoinColumn {
|
||||
|
||||
/**
|
||||
* The local database column name.
|
||||
*/
|
||||
String localDbColumn;
|
||||
|
||||
/**
|
||||
* The foreign database column name.
|
||||
*/
|
||||
String foreignDbColumn;
|
||||
|
||||
boolean insertable;
|
||||
|
||||
boolean updateable;
|
||||
|
||||
/**
|
||||
* Construct when automatically determining the join.
|
||||
* <p>
|
||||
* Assume that we want the foreign key to be insertable and updateable.
|
||||
* </p>
|
||||
*/
|
||||
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn) {
|
||||
this(localDbColumn, foreignDbColumn, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with explicit insertable and updateable flags.
|
||||
*/
|
||||
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn, boolean insertable, boolean updateable) {
|
||||
this.localDbColumn = nullEmptyString(localDbColumn);
|
||||
this.foreignDbColumn = nullEmptyString(foreignDbColumn);
|
||||
this.insertable = insertable;
|
||||
this.updateable = updateable;
|
||||
}
|
||||
|
||||
public DeployTableJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
this(jc.referencedColumnName(), jc.name(), jc.insertable(), jc.updatable());
|
||||
setReferencedColumn(beanTable);
|
||||
if (!order){
|
||||
reverse();
|
||||
}
|
||||
}
|
||||
|
||||
private void setReferencedColumn(BeanTable beanTable){
|
||||
if (localDbColumn == null){
|
||||
BeanProperty[] idProperties = beanTable.getIdProperties();
|
||||
if (idProperties.length == 1){
|
||||
localDbColumn = idProperties[0].getDbColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the direction of the join.
|
||||
*/
|
||||
public DeployTableJoinColumn reverse() {
|
||||
String temp = localDbColumn;
|
||||
localDbColumn = foreignDbColumn;
|
||||
foreignDbColumn = temp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to null out empty strings.
|
||||
*/
|
||||
private String nullEmptyString(String s){
|
||||
if ("".equals(s)){
|
||||
return null;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
public DeployTableJoinColumn copy(boolean reverse) {
|
||||
// Note that the insertable and updateable are just copied
|
||||
// which may not always be the correct thing to do
|
||||
// but will leave it like this for now
|
||||
if (reverse){
|
||||
return new DeployTableJoinColumn(foreignDbColumn, localDbColumn, insertable, updateable);
|
||||
|
||||
} else {
|
||||
return new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return localDbColumn + " = " + foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if either the local or foreign column is null.
|
||||
* <p>
|
||||
* Both columns need to be defined. If one is null then typically it is
|
||||
* derived as the primary key column.
|
||||
* </p>
|
||||
*/
|
||||
public boolean hasNullColumn() {
|
||||
return localDbColumn == null || foreignDbColumn == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* When only ONE column has been set by deployment information return that one.
|
||||
* <p>
|
||||
* Used with hasNullColumn() to set the foreignDbColumn for OneToMany joins.
|
||||
* </p>
|
||||
*/
|
||||
public String getNonNullColumn() {
|
||||
if (localDbColumn == null && foreignDbColumn == null) {
|
||||
throw new IllegalStateException("expecting only one null column?");
|
||||
|
||||
} else if (localDbColumn != null && foreignDbColumn != null) {
|
||||
throw new IllegalStateException("expecting one null column?");
|
||||
}
|
||||
if (localDbColumn != null) {
|
||||
return localDbColumn;
|
||||
} else {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return updateable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column name.
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the foreign database column name.
|
||||
* <p>
|
||||
* Used when this is derived from Primary Key and not set explicitly in the
|
||||
* deployment information.
|
||||
* </p>
|
||||
*/
|
||||
public void setForeignDbColumn(String foreignDbColumn) {
|
||||
this.foreignDbColumn = foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local database column name.
|
||||
*/
|
||||
public String getLocalDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the local database column name.
|
||||
*/
|
||||
public void setLocalDbColumn(String localDbColumn) {
|
||||
this.localDbColumn = localDbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
|
||||
/**
|
||||
* A join pair of local and foreign properties.
|
||||
*/
|
||||
public class DeployTableJoinColumn {
|
||||
|
||||
/**
|
||||
* The local database column name.
|
||||
*/
|
||||
String localDbColumn;
|
||||
|
||||
/**
|
||||
* The foreign database column name.
|
||||
*/
|
||||
String foreignDbColumn;
|
||||
|
||||
boolean insertable;
|
||||
|
||||
boolean updateable;
|
||||
|
||||
/**
|
||||
* Construct when automatically determining the join.
|
||||
* <p>
|
||||
* Assume that we want the foreign key to be insertable and updateable.
|
||||
* </p>
|
||||
*/
|
||||
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn) {
|
||||
this(localDbColumn, foreignDbColumn, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with explicit insertable and updateable flags.
|
||||
*/
|
||||
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn, boolean insertable, boolean updateable) {
|
||||
this.localDbColumn = nullEmptyString(localDbColumn);
|
||||
this.foreignDbColumn = nullEmptyString(foreignDbColumn);
|
||||
this.insertable = insertable;
|
||||
this.updateable = updateable;
|
||||
}
|
||||
|
||||
public DeployTableJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
this(jc.referencedColumnName(), jc.name(), jc.insertable(), jc.updatable());
|
||||
setReferencedColumn(beanTable);
|
||||
if (!order){
|
||||
reverse();
|
||||
}
|
||||
}
|
||||
|
||||
private void setReferencedColumn(BeanTable beanTable){
|
||||
if (localDbColumn == null){
|
||||
BeanProperty[] idProperties = beanTable.getIdProperties();
|
||||
if (idProperties.length == 1){
|
||||
localDbColumn = idProperties[0].getDbColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the direction of the join.
|
||||
*/
|
||||
public DeployTableJoinColumn reverse() {
|
||||
String temp = localDbColumn;
|
||||
localDbColumn = foreignDbColumn;
|
||||
foreignDbColumn = temp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to null out empty strings.
|
||||
*/
|
||||
private String nullEmptyString(String s){
|
||||
if ("".equals(s)){
|
||||
return null;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
public DeployTableJoinColumn copy(boolean reverse) {
|
||||
// Note that the insertable and updateable are just copied
|
||||
// which may not always be the correct thing to do
|
||||
// but will leave it like this for now
|
||||
if (reverse){
|
||||
return new DeployTableJoinColumn(foreignDbColumn, localDbColumn, insertable, updateable);
|
||||
|
||||
} else {
|
||||
return new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return localDbColumn + " = " + foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if either the local or foreign column is null.
|
||||
* <p>
|
||||
* Both columns need to be defined. If one is null then typically it is
|
||||
* derived as the primary key column.
|
||||
* </p>
|
||||
*/
|
||||
public boolean hasNullColumn() {
|
||||
return localDbColumn == null || foreignDbColumn == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* When only ONE column has been set by deployment information return that one.
|
||||
* <p>
|
||||
* Used with hasNullColumn() to set the foreignDbColumn for OneToMany joins.
|
||||
* </p>
|
||||
*/
|
||||
public String getNonNullColumn() {
|
||||
if (localDbColumn == null && foreignDbColumn == null) {
|
||||
throw new IllegalStateException("expecting only one null column?");
|
||||
|
||||
} else if (localDbColumn != null && foreignDbColumn != null) {
|
||||
throw new IllegalStateException("expecting one null column?");
|
||||
}
|
||||
if (localDbColumn != null) {
|
||||
return localDbColumn;
|
||||
} else {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return updateable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column name.
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the foreign database column name.
|
||||
* <p>
|
||||
* Used when this is derived from Primary Key and not set explicitly in the
|
||||
* deployment information.
|
||||
* </p>
|
||||
*/
|
||||
public void setForeignDbColumn(String foreignDbColumn) {
|
||||
this.foreignDbColumn = foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local database column name.
|
||||
*/
|
||||
public String getLocalDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the local database column name.
|
||||
*/
|
||||
public void setLocalDbColumn(String localDbColumn) {
|
||||
this.localDbColumn = localDbColumn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+319
-319
@@ -1,319 +1,319 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.MapKey;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
|
||||
import com.avaje.ebean.annotation.PrivateOwned;
|
||||
import com.avaje.ebean.annotation.Where;
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Read the deployment annotation for Assoc Many beans.
|
||||
*/
|
||||
public class AnnotationAssocManys extends AnnotationParser {
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the DeployInfo.
|
||||
*/
|
||||
public AnnotationAssocManys(DeployBeanInfo<?> info, BeanDescriptorManager factory) {
|
||||
super(info);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
for (DeployBeanProperty prop : descriptor.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssocMany<?>) {
|
||||
read((DeployBeanPropertyAssocMany<?>) prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void read(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
OneToMany oneToMany = get(prop, OneToMany.class);
|
||||
if (oneToMany != null) {
|
||||
readToOne(oneToMany, prop);
|
||||
PrivateOwned privateOwned = get(prop, PrivateOwned.class);
|
||||
if (privateOwned != null){
|
||||
prop.setModifyListenMode(ModifyListenMode.REMOVALS);
|
||||
prop.getCascadeInfo().setDelete(privateOwned.cascadeRemove());
|
||||
}
|
||||
}
|
||||
ManyToMany manyToMany = get(prop, ManyToMany.class);
|
||||
if (manyToMany != null) {
|
||||
readToMany(manyToMany, prop);
|
||||
}
|
||||
|
||||
OrderBy orderBy = get(prop, OrderBy.class);
|
||||
if (orderBy != null) {
|
||||
prop.setFetchOrderBy(orderBy.value());
|
||||
}
|
||||
|
||||
MapKey mapKey = get(prop, MapKey.class);
|
||||
if (mapKey != null) {
|
||||
prop.setMapKey(mapKey.name());
|
||||
}
|
||||
|
||||
Where where = get(prop, Where.class);
|
||||
if (where != null) {
|
||||
prop.setExtraWhere(where.clause());
|
||||
}
|
||||
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
JoinColumn joinColumn = get(prop, JoinColumn.class);
|
||||
if (joinColumn != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumn, beanTable);
|
||||
}
|
||||
|
||||
JoinColumns joinColumns = get(prop, JoinColumns.class);
|
||||
if (joinColumns != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumns.value(), beanTable);
|
||||
}
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
if (prop.isManyToMany()){
|
||||
// expected this
|
||||
readJoinTable(joinTable, prop);
|
||||
|
||||
} else {
|
||||
// OneToMany in theory
|
||||
prop.getTableJoin().addJoinColumn(true, joinTable.joinColumns(), beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
if (prop.getMappedBy() != null){
|
||||
// the join is derived by reversing the join information
|
||||
// from the mapped by property.
|
||||
// Refer BeanDescriptorManager.readEntityRelationships()
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop.isManyToMany()){
|
||||
manyToManyDefaultJoins(prop);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!prop.getTableJoin().hasJoinColumns() && beanTable != null){
|
||||
|
||||
// use naming convention to define join (based on the bean name for this side of relationship)
|
||||
// A unidirectional OneToMany or OneToMany with no mappedBy property
|
||||
|
||||
NamingConvention nc = factory.getNamingConvention();
|
||||
|
||||
String fkeyPrefix = null;
|
||||
if (nc.isUseForeignKeyPrefix()){
|
||||
fkeyPrefix = nc.getColumnFromProperty(descriptor.getBeanType(), descriptor.getName());
|
||||
}
|
||||
|
||||
// Use the owning bean table to define the join
|
||||
BeanTable owningBeanTable = factory.getBeanTable(descriptor.getBeanType());
|
||||
owningBeanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the joins for a ManyToMany relationship.
|
||||
* <p>
|
||||
* This includes joins to the intersection table and from the intersection table
|
||||
* to the other side of the ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
private void readJoinTable(JoinTable joinTable, DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
String intTableName = getFullTableName(joinTable);
|
||||
// set the intersection table
|
||||
DeployTableJoin intJoin = new DeployTableJoin();
|
||||
intJoin.setTable(intTableName);
|
||||
|
||||
// add the source to intersection join columns
|
||||
intJoin.addJoinColumn(true, joinTable.joinColumns(), prop.getBeanTable());
|
||||
|
||||
// set the intersection to dest table join columns
|
||||
DeployTableJoin destJoin = prop.getTableJoin();
|
||||
destJoin.addJoinColumn(false, joinTable.inverseJoinColumns(), prop.getBeanTable());
|
||||
|
||||
intJoin.setType(SqlJoinType.OUTER);
|
||||
|
||||
// reverse join from dest back to intersection
|
||||
DeployTableJoin inverseDest = destJoin.createInverse(intTableName);
|
||||
prop.setIntersectionJoin(intJoin);
|
||||
prop.setInverseJoin(inverseDest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full table name
|
||||
* @param joinTable
|
||||
* @return
|
||||
*/
|
||||
private String getFullTableName(JoinTable joinTable) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!StringHelper.isNull(joinTable.catalog())){
|
||||
sb.append(joinTable.catalog()).append(".");
|
||||
}
|
||||
if (!StringHelper.isNull(joinTable.schema())){
|
||||
sb.append(joinTable.schema()).append(".");
|
||||
}
|
||||
sb.append(joinTable.name());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define intersection table and foreign key columns for ManyToMany.
|
||||
* <p>
|
||||
* Some of these (maybe all) have been already defined via @JoinTable
|
||||
* and @JoinColumns etc.
|
||||
* </p>
|
||||
*/
|
||||
private void manyToManyDefaultJoins(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
String intTableName = null;
|
||||
|
||||
DeployTableJoin intJoin = prop.getIntersectionJoin();
|
||||
if (intJoin == null){
|
||||
intJoin = new DeployTableJoin();
|
||||
prop.setIntersectionJoin(intJoin);
|
||||
} else {
|
||||
// intersection table already defined (by @JoinTable)
|
||||
intTableName = intJoin.getTable();
|
||||
}
|
||||
|
||||
BeanTable localTable = factory.getBeanTable(descriptor.getBeanType());
|
||||
BeanTable otherTable = factory.getBeanTable(prop.getTargetType());
|
||||
|
||||
final String localTableName = localTable.getUnqualifiedBaseTable();
|
||||
final String otherTableName = otherTable.getUnqualifiedBaseTable();
|
||||
|
||||
if (intTableName == null){
|
||||
// define intersection table name
|
||||
intTableName = getM2MJoinTableName(localTable, otherTable);
|
||||
|
||||
intJoin.setTable(intTableName);
|
||||
intJoin.setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
DeployTableJoin destJoin = prop.getTableJoin();
|
||||
|
||||
|
||||
if (intJoin.hasJoinColumns() && destJoin.hasJoinColumns()){
|
||||
// already defined the foreign key columns etc
|
||||
return;
|
||||
}
|
||||
if (!intJoin.hasJoinColumns()){
|
||||
// define foreign key columns
|
||||
BeanProperty[] localIds = localTable.getIdProperties();
|
||||
for (int i = 0; i < localIds.length; i++) {
|
||||
// add the source to intersection join columns
|
||||
String fkCol = localTableName+"_"+localIds[i].getDbColumn();
|
||||
intJoin.addJoinColumn(new DeployTableJoinColumn(localIds[i].getDbColumn(), fkCol));
|
||||
}
|
||||
}
|
||||
|
||||
if (!destJoin.hasJoinColumns()){
|
||||
// define inverse foreign key columns
|
||||
BeanProperty[] otherIds = otherTable.getIdProperties();
|
||||
for (int i = 0; i < otherIds.length; i++) {
|
||||
// set the intersection to dest table join columns
|
||||
final String fkCol = otherTableName+"_"+otherIds[i].getDbColumn();
|
||||
destJoin.addJoinColumn(new DeployTableJoinColumn(fkCol, otherIds[i].getDbColumn()));
|
||||
}
|
||||
}
|
||||
|
||||
// reverse join from dest back to intersection
|
||||
DeployTableJoin inverseDest = destJoin.createInverse(intTableName);
|
||||
prop.setInverseJoin(inverseDest);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to ["+type+"] from ["+from+"]. Is "+type+" registered?";
|
||||
}
|
||||
|
||||
private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
|
||||
Class<?> targetType = propAnn.targetEntity();
|
||||
if (targetType.equals(void.class)) {
|
||||
// via reflection of generics type
|
||||
targetType = manyProp.getTargetType();
|
||||
} else {
|
||||
manyProp.setTargetType(targetType);
|
||||
}
|
||||
|
||||
// find the other many table (not intersection)
|
||||
BeanTable assoc = factory.getBeanTable(targetType);
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
manyProp.setManyToMany(true);
|
||||
manyProp.setModifyListenMode(ModifyListenMode.ALL);
|
||||
manyProp.setBeanTable(assoc);
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
|
||||
Class<?> targetType = propAnn.targetEntity();
|
||||
if (targetType.equals(void.class)) {
|
||||
// via reflection of generics type
|
||||
targetType = manyProp.getTargetType();
|
||||
} else {
|
||||
manyProp.setTargetType(targetType);
|
||||
}
|
||||
|
||||
BeanTable assoc = factory.getBeanTable(targetType);
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
manyProp.setBeanTable(assoc);
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
|
||||
private String getM2MJoinTableName(BeanTable lhsTable, BeanTable rhsTable){
|
||||
|
||||
TableName lhs = new TableName(lhsTable.getBaseTable());
|
||||
TableName rhs = new TableName(rhsTable.getBaseTable());
|
||||
|
||||
TableName joinTable = namingConvention.getM2MJoinTableName(lhs, rhs);
|
||||
|
||||
return joinTable.getQualifiedName();
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.MapKey;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
|
||||
import com.avaje.ebean.annotation.PrivateOwned;
|
||||
import com.avaje.ebean.annotation.Where;
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Read the deployment annotation for Assoc Many beans.
|
||||
*/
|
||||
public class AnnotationAssocManys extends AnnotationParser {
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the DeployInfo.
|
||||
*/
|
||||
public AnnotationAssocManys(DeployBeanInfo<?> info, BeanDescriptorManager factory) {
|
||||
super(info);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
for (DeployBeanProperty prop : descriptor.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssocMany<?>) {
|
||||
read((DeployBeanPropertyAssocMany<?>) prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void read(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
OneToMany oneToMany = get(prop, OneToMany.class);
|
||||
if (oneToMany != null) {
|
||||
readToOne(oneToMany, prop);
|
||||
PrivateOwned privateOwned = get(prop, PrivateOwned.class);
|
||||
if (privateOwned != null){
|
||||
prop.setModifyListenMode(ModifyListenMode.REMOVALS);
|
||||
prop.getCascadeInfo().setDelete(privateOwned.cascadeRemove());
|
||||
}
|
||||
}
|
||||
ManyToMany manyToMany = get(prop, ManyToMany.class);
|
||||
if (manyToMany != null) {
|
||||
readToMany(manyToMany, prop);
|
||||
}
|
||||
|
||||
OrderBy orderBy = get(prop, OrderBy.class);
|
||||
if (orderBy != null) {
|
||||
prop.setFetchOrderBy(orderBy.value());
|
||||
}
|
||||
|
||||
MapKey mapKey = get(prop, MapKey.class);
|
||||
if (mapKey != null) {
|
||||
prop.setMapKey(mapKey.name());
|
||||
}
|
||||
|
||||
Where where = get(prop, Where.class);
|
||||
if (where != null) {
|
||||
prop.setExtraWhere(where.clause());
|
||||
}
|
||||
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
JoinColumn joinColumn = get(prop, JoinColumn.class);
|
||||
if (joinColumn != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumn, beanTable);
|
||||
}
|
||||
|
||||
JoinColumns joinColumns = get(prop, JoinColumns.class);
|
||||
if (joinColumns != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumns.value(), beanTable);
|
||||
}
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
if (prop.isManyToMany()){
|
||||
// expected this
|
||||
readJoinTable(joinTable, prop);
|
||||
|
||||
} else {
|
||||
// OneToMany in theory
|
||||
prop.getTableJoin().addJoinColumn(true, joinTable.joinColumns(), beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
if (prop.getMappedBy() != null){
|
||||
// the join is derived by reversing the join information
|
||||
// from the mapped by property.
|
||||
// Refer BeanDescriptorManager.readEntityRelationships()
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop.isManyToMany()){
|
||||
manyToManyDefaultJoins(prop);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!prop.getTableJoin().hasJoinColumns() && beanTable != null){
|
||||
|
||||
// use naming convention to define join (based on the bean name for this side of relationship)
|
||||
// A unidirectional OneToMany or OneToMany with no mappedBy property
|
||||
|
||||
NamingConvention nc = factory.getNamingConvention();
|
||||
|
||||
String fkeyPrefix = null;
|
||||
if (nc.isUseForeignKeyPrefix()){
|
||||
fkeyPrefix = nc.getColumnFromProperty(descriptor.getBeanType(), descriptor.getName());
|
||||
}
|
||||
|
||||
// Use the owning bean table to define the join
|
||||
BeanTable owningBeanTable = factory.getBeanTable(descriptor.getBeanType());
|
||||
owningBeanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the joins for a ManyToMany relationship.
|
||||
* <p>
|
||||
* This includes joins to the intersection table and from the intersection table
|
||||
* to the other side of the ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
private void readJoinTable(JoinTable joinTable, DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
String intTableName = getFullTableName(joinTable);
|
||||
// set the intersection table
|
||||
DeployTableJoin intJoin = new DeployTableJoin();
|
||||
intJoin.setTable(intTableName);
|
||||
|
||||
// add the source to intersection join columns
|
||||
intJoin.addJoinColumn(true, joinTable.joinColumns(), prop.getBeanTable());
|
||||
|
||||
// set the intersection to dest table join columns
|
||||
DeployTableJoin destJoin = prop.getTableJoin();
|
||||
destJoin.addJoinColumn(false, joinTable.inverseJoinColumns(), prop.getBeanTable());
|
||||
|
||||
intJoin.setType(SqlJoinType.OUTER);
|
||||
|
||||
// reverse join from dest back to intersection
|
||||
DeployTableJoin inverseDest = destJoin.createInverse(intTableName);
|
||||
prop.setIntersectionJoin(intJoin);
|
||||
prop.setInverseJoin(inverseDest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full table name
|
||||
* @param joinTable
|
||||
* @return
|
||||
*/
|
||||
private String getFullTableName(JoinTable joinTable) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!StringHelper.isNull(joinTable.catalog())){
|
||||
sb.append(joinTable.catalog()).append(".");
|
||||
}
|
||||
if (!StringHelper.isNull(joinTable.schema())){
|
||||
sb.append(joinTable.schema()).append(".");
|
||||
}
|
||||
sb.append(joinTable.name());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define intersection table and foreign key columns for ManyToMany.
|
||||
* <p>
|
||||
* Some of these (maybe all) have been already defined via @JoinTable
|
||||
* and @JoinColumns etc.
|
||||
* </p>
|
||||
*/
|
||||
private void manyToManyDefaultJoins(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
String intTableName = null;
|
||||
|
||||
DeployTableJoin intJoin = prop.getIntersectionJoin();
|
||||
if (intJoin == null){
|
||||
intJoin = new DeployTableJoin();
|
||||
prop.setIntersectionJoin(intJoin);
|
||||
} else {
|
||||
// intersection table already defined (by @JoinTable)
|
||||
intTableName = intJoin.getTable();
|
||||
}
|
||||
|
||||
BeanTable localTable = factory.getBeanTable(descriptor.getBeanType());
|
||||
BeanTable otherTable = factory.getBeanTable(prop.getTargetType());
|
||||
|
||||
final String localTableName = localTable.getUnqualifiedBaseTable();
|
||||
final String otherTableName = otherTable.getUnqualifiedBaseTable();
|
||||
|
||||
if (intTableName == null){
|
||||
// define intersection table name
|
||||
intTableName = getM2MJoinTableName(localTable, otherTable);
|
||||
|
||||
intJoin.setTable(intTableName);
|
||||
intJoin.setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
DeployTableJoin destJoin = prop.getTableJoin();
|
||||
|
||||
|
||||
if (intJoin.hasJoinColumns() && destJoin.hasJoinColumns()){
|
||||
// already defined the foreign key columns etc
|
||||
return;
|
||||
}
|
||||
if (!intJoin.hasJoinColumns()){
|
||||
// define foreign key columns
|
||||
BeanProperty[] localIds = localTable.getIdProperties();
|
||||
for (int i = 0; i < localIds.length; i++) {
|
||||
// add the source to intersection join columns
|
||||
String fkCol = localTableName+"_"+localIds[i].getDbColumn();
|
||||
intJoin.addJoinColumn(new DeployTableJoinColumn(localIds[i].getDbColumn(), fkCol));
|
||||
}
|
||||
}
|
||||
|
||||
if (!destJoin.hasJoinColumns()){
|
||||
// define inverse foreign key columns
|
||||
BeanProperty[] otherIds = otherTable.getIdProperties();
|
||||
for (int i = 0; i < otherIds.length; i++) {
|
||||
// set the intersection to dest table join columns
|
||||
final String fkCol = otherTableName+"_"+otherIds[i].getDbColumn();
|
||||
destJoin.addJoinColumn(new DeployTableJoinColumn(fkCol, otherIds[i].getDbColumn()));
|
||||
}
|
||||
}
|
||||
|
||||
// reverse join from dest back to intersection
|
||||
DeployTableJoin inverseDest = destJoin.createInverse(intTableName);
|
||||
prop.setInverseJoin(inverseDest);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to ["+type+"] from ["+from+"]. Is "+type+" registered?";
|
||||
}
|
||||
|
||||
private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
|
||||
Class<?> targetType = propAnn.targetEntity();
|
||||
if (targetType.equals(void.class)) {
|
||||
// via reflection of generics type
|
||||
targetType = manyProp.getTargetType();
|
||||
} else {
|
||||
manyProp.setTargetType(targetType);
|
||||
}
|
||||
|
||||
// find the other many table (not intersection)
|
||||
BeanTable assoc = factory.getBeanTable(targetType);
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
manyProp.setManyToMany(true);
|
||||
manyProp.setModifyListenMode(ModifyListenMode.ALL);
|
||||
manyProp.setBeanTable(assoc);
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
|
||||
Class<?> targetType = propAnn.targetEntity();
|
||||
if (targetType.equals(void.class)) {
|
||||
// via reflection of generics type
|
||||
targetType = manyProp.getTargetType();
|
||||
} else {
|
||||
manyProp.setTargetType(targetType);
|
||||
}
|
||||
|
||||
BeanTable assoc = factory.getBeanTable(targetType);
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
manyProp.setBeanTable(assoc);
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
|
||||
private String getM2MJoinTableName(BeanTable lhsTable, BeanTable rhsTable){
|
||||
|
||||
TableName lhs = new TableName(lhsTable.getBaseTable());
|
||||
TableName rhs = new TableName(rhsTable.getBaseTable());
|
||||
|
||||
TableName joinTable = namingConvention.getM2MJoinTableName(lhs, rhs);
|
||||
|
||||
return joinTable.getQualifiedName();
|
||||
}
|
||||
}
|
||||
|
||||
+213
-213
@@ -1,213 +1,213 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.avaje.ebean.annotation.EmbeddedColumns;
|
||||
import com.avaje.ebean.annotation.Where;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Read the deployment annotations for Associated One beans.
|
||||
*/
|
||||
public class AnnotationAssocOnes extends AnnotationParser {
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the deploy Info.
|
||||
*/
|
||||
public AnnotationAssocOnes(DeployBeanInfo<?> info, BeanDescriptorManager factory) {
|
||||
super(info);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the annotation.
|
||||
*/
|
||||
public void parse() {
|
||||
|
||||
for (DeployBeanProperty prop : descriptor.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
readAssocOne((DeployBeanPropertyAssocOne<?>) prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readAssocOne(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
ManyToOne manyToOne = get(prop, ManyToOne.class);
|
||||
if (manyToOne != null) {
|
||||
readManyToOne(manyToOne, prop);
|
||||
}
|
||||
OneToOne oneToOne = get(prop, OneToOne.class);
|
||||
if (oneToOne != null) {
|
||||
readOneToOne(oneToOne, prop);
|
||||
}
|
||||
Embedded embedded = get(prop, Embedded.class);
|
||||
if (embedded != null) {
|
||||
readEmbedded(embedded, prop);
|
||||
}
|
||||
EmbeddedId emId = get(prop, EmbeddedId.class);
|
||||
if (emId != null) {
|
||||
prop.setEmbedded(true);
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
}
|
||||
Column column = get(prop, Column.class);
|
||||
if (column != null && !isEmpty(column.name())) {
|
||||
// have this in for AssocOnes used on
|
||||
// Sql based beans...
|
||||
prop.setDbColumn(column.name());
|
||||
}
|
||||
|
||||
// May as well check for Id. Makes sense to me.
|
||||
Id id = get(prop, Id.class);
|
||||
if (id != null) {
|
||||
prop.setEmbedded(true);
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
Where where = get(prop, Where.class);
|
||||
if (where != null) {
|
||||
// not expecting this to be used on assoc one properties
|
||||
prop.setExtraWhere(where.clause());
|
||||
}
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null) {
|
||||
prop.setNullable(false);
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
}
|
||||
}
|
||||
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
JoinColumn joinColumn = get(prop, JoinColumn.class);
|
||||
if (joinColumn != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable);
|
||||
if (!joinColumn.updatable()) {
|
||||
prop.setDbUpdateable(false);
|
||||
}
|
||||
if (!joinColumn.nullable()) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
}
|
||||
|
||||
JoinColumns joinColumns = get(prop, JoinColumns.class);
|
||||
if (joinColumns != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumns.value(), beanTable);
|
||||
}
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinTable.joinColumns(), beanTable);
|
||||
}
|
||||
|
||||
info.setBeanJoinType(prop, prop.isNullable());
|
||||
|
||||
if (!prop.getTableJoin().hasJoinColumns() && beanTable != null) {
|
||||
|
||||
if (prop.getMappedBy() != null) {
|
||||
// the join is derived by reversing the join information
|
||||
// from the mapped by property.
|
||||
// Refer BeanDescriptorManager.readEntityRelationships()
|
||||
|
||||
} else {
|
||||
// use naming convention to define join.
|
||||
NamingConvention nc = factory.getNamingConvention();
|
||||
|
||||
String fkeyPrefix = null;
|
||||
if (nc.isUseForeignKeyPrefix()){
|
||||
fkeyPrefix = nc.getColumnFromProperty(beanType, prop.getName());
|
||||
}
|
||||
|
||||
beanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered?";
|
||||
}
|
||||
|
||||
private void readManyToOne(ManyToOne propAnn, DeployBeanProperty prop) {
|
||||
|
||||
DeployBeanPropertyAssocOne<?> beanProp = (DeployBeanPropertyAssocOne<?>) prop;
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), beanProp.getCascadeInfo());
|
||||
|
||||
BeanTable assoc = factory.getBeanTable(beanProp.getPropertyType());
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(beanProp.getPropertyType(), prop.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
beanProp.setBeanTable(assoc);
|
||||
beanProp.setDbInsertable(true);
|
||||
beanProp.setDbUpdateable(true);
|
||||
beanProp.setNullable(propAnn.optional());
|
||||
beanProp.setFetchType(propAnn.fetch());
|
||||
}
|
||||
|
||||
private void readOneToOne(OneToOne propAnn, DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
prop.setOneToOne(true);
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
prop.setNullable(propAnn.optional());
|
||||
prop.setFetchType(propAnn.fetch());
|
||||
prop.setMappedBy(propAnn.mappedBy());
|
||||
if (!"".equals(propAnn.mappedBy())) {
|
||||
prop.setOneToOneExported(true);
|
||||
}
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo());
|
||||
|
||||
BeanTable assoc = factory.getBeanTable(prop.getPropertyType());
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
prop.setBeanTable(assoc);
|
||||
}
|
||||
|
||||
private void readEmbedded(Embedded propAnn, DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
prop.setEmbedded(true);
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
|
||||
EmbeddedColumns columns = get(prop, EmbeddedColumns.class);
|
||||
if (columns != null) {
|
||||
|
||||
// convert into a Map
|
||||
String propColumns = columns.columns();
|
||||
Map<String, String> propMap = StringHelper.delimitedToMap(propColumns, ",", "=");
|
||||
|
||||
prop.getDeployEmbedded().putAll(propMap);
|
||||
}
|
||||
|
||||
readEmbeddedAttributeOverrides(prop);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.avaje.ebean.annotation.EmbeddedColumns;
|
||||
import com.avaje.ebean.annotation.Where;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Read the deployment annotations for Associated One beans.
|
||||
*/
|
||||
public class AnnotationAssocOnes extends AnnotationParser {
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the deploy Info.
|
||||
*/
|
||||
public AnnotationAssocOnes(DeployBeanInfo<?> info, BeanDescriptorManager factory) {
|
||||
super(info);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the annotation.
|
||||
*/
|
||||
public void parse() {
|
||||
|
||||
for (DeployBeanProperty prop : descriptor.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
readAssocOne((DeployBeanPropertyAssocOne<?>) prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readAssocOne(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
ManyToOne manyToOne = get(prop, ManyToOne.class);
|
||||
if (manyToOne != null) {
|
||||
readManyToOne(manyToOne, prop);
|
||||
}
|
||||
OneToOne oneToOne = get(prop, OneToOne.class);
|
||||
if (oneToOne != null) {
|
||||
readOneToOne(oneToOne, prop);
|
||||
}
|
||||
Embedded embedded = get(prop, Embedded.class);
|
||||
if (embedded != null) {
|
||||
readEmbedded(embedded, prop);
|
||||
}
|
||||
EmbeddedId emId = get(prop, EmbeddedId.class);
|
||||
if (emId != null) {
|
||||
prop.setEmbedded(true);
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
}
|
||||
Column column = get(prop, Column.class);
|
||||
if (column != null && !isEmpty(column.name())) {
|
||||
// have this in for AssocOnes used on
|
||||
// Sql based beans...
|
||||
prop.setDbColumn(column.name());
|
||||
}
|
||||
|
||||
// May as well check for Id. Makes sense to me.
|
||||
Id id = get(prop, Id.class);
|
||||
if (id != null) {
|
||||
prop.setEmbedded(true);
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
Where where = get(prop, Where.class);
|
||||
if (where != null) {
|
||||
// not expecting this to be used on assoc one properties
|
||||
prop.setExtraWhere(where.clause());
|
||||
}
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null) {
|
||||
prop.setNullable(false);
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
}
|
||||
}
|
||||
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
JoinColumn joinColumn = get(prop, JoinColumn.class);
|
||||
if (joinColumn != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable);
|
||||
if (!joinColumn.updatable()) {
|
||||
prop.setDbUpdateable(false);
|
||||
}
|
||||
if (!joinColumn.nullable()) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
}
|
||||
|
||||
JoinColumns joinColumns = get(prop, JoinColumns.class);
|
||||
if (joinColumns != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumns.value(), beanTable);
|
||||
}
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinTable.joinColumns(), beanTable);
|
||||
}
|
||||
|
||||
info.setBeanJoinType(prop, prop.isNullable());
|
||||
|
||||
if (!prop.getTableJoin().hasJoinColumns() && beanTable != null) {
|
||||
|
||||
if (prop.getMappedBy() != null) {
|
||||
// the join is derived by reversing the join information
|
||||
// from the mapped by property.
|
||||
// Refer BeanDescriptorManager.readEntityRelationships()
|
||||
|
||||
} else {
|
||||
// use naming convention to define join.
|
||||
NamingConvention nc = factory.getNamingConvention();
|
||||
|
||||
String fkeyPrefix = null;
|
||||
if (nc.isUseForeignKeyPrefix()){
|
||||
fkeyPrefix = nc.getColumnFromProperty(beanType, prop.getName());
|
||||
}
|
||||
|
||||
beanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered?";
|
||||
}
|
||||
|
||||
private void readManyToOne(ManyToOne propAnn, DeployBeanProperty prop) {
|
||||
|
||||
DeployBeanPropertyAssocOne<?> beanProp = (DeployBeanPropertyAssocOne<?>) prop;
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), beanProp.getCascadeInfo());
|
||||
|
||||
BeanTable assoc = factory.getBeanTable(beanProp.getPropertyType());
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(beanProp.getPropertyType(), prop.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
beanProp.setBeanTable(assoc);
|
||||
beanProp.setDbInsertable(true);
|
||||
beanProp.setDbUpdateable(true);
|
||||
beanProp.setNullable(propAnn.optional());
|
||||
beanProp.setFetchType(propAnn.fetch());
|
||||
}
|
||||
|
||||
private void readOneToOne(OneToOne propAnn, DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
prop.setOneToOne(true);
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
prop.setNullable(propAnn.optional());
|
||||
prop.setFetchType(propAnn.fetch());
|
||||
prop.setMappedBy(propAnn.mappedBy());
|
||||
if (!"".equals(propAnn.mappedBy())) {
|
||||
prop.setOneToOneExported(true);
|
||||
}
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo());
|
||||
|
||||
BeanTable assoc = factory.getBeanTable(prop.getPropertyType());
|
||||
if (assoc == null) {
|
||||
String msg = errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
prop.setBeanTable(assoc);
|
||||
}
|
||||
|
||||
private void readEmbedded(Embedded propAnn, DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
prop.setEmbedded(true);
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
|
||||
EmbeddedColumns columns = get(prop, EmbeddedColumns.class);
|
||||
if (columns != null) {
|
||||
|
||||
// convert into a Map
|
||||
String propColumns = columns.columns();
|
||||
Map<String, String> propMap = StringHelper.delimitedToMap(propColumns, ",", "=");
|
||||
|
||||
prop.getDeployEmbedded().putAll(propMap);
|
||||
}
|
||||
|
||||
readEmbeddedAttributeOverrides(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-31
@@ -1,31 +1,31 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
|
||||
/**
|
||||
* Read the annotations for BeanTable.
|
||||
* <p>
|
||||
* Refer to BeanTable but basically determining base table, table alias
|
||||
* and the unique id properties.
|
||||
* </p>
|
||||
*/
|
||||
public class AnnotationBeanTable extends AnnotationBase {
|
||||
|
||||
final DeployBeanTable beanTable;
|
||||
|
||||
public AnnotationBeanTable(DeployUtil util, DeployBeanTable beanTable){
|
||||
super(util);
|
||||
this.beanTable = beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
|
||||
TableName tableName = namingConvention.getTableName(beanTable.getBeanType());
|
||||
|
||||
beanTable.setBaseTable(tableName.getQualifiedName());
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
|
||||
/**
|
||||
* Read the annotations for BeanTable.
|
||||
* <p>
|
||||
* Refer to BeanTable but basically determining base table, table alias
|
||||
* and the unique id properties.
|
||||
* </p>
|
||||
*/
|
||||
public class AnnotationBeanTable extends AnnotationBase {
|
||||
|
||||
final DeployBeanTable beanTable;
|
||||
|
||||
public AnnotationBeanTable(DeployUtil util, DeployBeanTable beanTable){
|
||||
super(util);
|
||||
this.beanTable = beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
|
||||
TableName tableName = namingConvention.getTableName(beanTable.getBeanType());
|
||||
|
||||
beanTable.setBaseTable(tableName.getQualifiedName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +1,169 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.annotation.CacheTuning;
|
||||
import com.avaje.ebean.annotation.EntityConcurrencyMode;
|
||||
import com.avaje.ebean.annotation.NamedUpdate;
|
||||
import com.avaje.ebean.annotation.NamedUpdates;
|
||||
import com.avaje.ebean.annotation.UpdateMode;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Read the class level deployment annotations.
|
||||
*/
|
||||
public class AnnotationClass extends AnnotationParser {
|
||||
|
||||
public AnnotationClass(DeployBeanInfo<?> info) {
|
||||
super(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the class level deployment annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
read(descriptor.getBeanType());
|
||||
setTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table name if it has not already been set.
|
||||
*/
|
||||
private void setTableName() {
|
||||
|
||||
if (descriptor.isBaseTableType()) {
|
||||
|
||||
// default the TableName using NamingConvention.
|
||||
TableName tableName = namingConvention.getTableName(descriptor.getBeanType());
|
||||
|
||||
descriptor.setBaseTable(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
private void read(Class<?> cls) {
|
||||
|
||||
Entity entity = cls.getAnnotation(Entity.class);
|
||||
if (entity != null) {
|
||||
if (entity.name().equals("")) {
|
||||
descriptor.setName(cls.getSimpleName());
|
||||
} else {
|
||||
descriptor.setName(entity.name());
|
||||
}
|
||||
}
|
||||
|
||||
Embeddable embeddable = cls.getAnnotation(Embeddable.class);
|
||||
if (embeddable != null) {
|
||||
descriptor.setEntityType(EntityType.EMBEDDED);
|
||||
descriptor.setName("Embeddable:" + cls.getSimpleName());
|
||||
}
|
||||
|
||||
UniqueConstraint uc = cls.getAnnotation(UniqueConstraint.class);
|
||||
if (uc != null) {
|
||||
descriptor.addCompoundUniqueConstraint(new CompoundUniqueContraint(uc.columnNames()));
|
||||
}
|
||||
|
||||
Table table = cls.getAnnotation(Table.class);
|
||||
if (table != null) {
|
||||
UniqueConstraint[] uniqueConstraints = table.uniqueConstraints();
|
||||
if (uniqueConstraints != null) {
|
||||
for (UniqueConstraint c : uniqueConstraints) {
|
||||
descriptor.addCompoundUniqueConstraint(new CompoundUniqueContraint(c.columnNames()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMode updateMode = cls.getAnnotation(UpdateMode.class);
|
||||
if (updateMode != null) {
|
||||
descriptor.setUpdateChangesOnly(updateMode.updateChangesOnly());
|
||||
}
|
||||
|
||||
NamedQueries namedQueries = cls.getAnnotation(NamedQueries.class);
|
||||
if (namedQueries != null) {
|
||||
readNamedQueries(namedQueries);
|
||||
}
|
||||
NamedQuery namedQuery = cls.getAnnotation(NamedQuery.class);
|
||||
if (namedQuery != null) {
|
||||
readNamedQuery(namedQuery);
|
||||
}
|
||||
|
||||
NamedUpdates namedUpdates = cls.getAnnotation(NamedUpdates.class);
|
||||
if (namedUpdates != null) {
|
||||
readNamedUpdates(namedUpdates);
|
||||
}
|
||||
|
||||
NamedUpdate namedUpdate = cls.getAnnotation(NamedUpdate.class);
|
||||
if (namedUpdate != null) {
|
||||
readNamedUpdate(namedUpdate);
|
||||
}
|
||||
|
||||
CacheStrategy cacheStrategy = cls.getAnnotation(CacheStrategy.class);
|
||||
CacheTuning cacheTuning = cls.getAnnotation(CacheTuning.class);
|
||||
if (cacheStrategy != null || cacheTuning != null) {
|
||||
readCacheStrategy(cacheStrategy, cacheTuning);
|
||||
}
|
||||
|
||||
EntityConcurrencyMode entityConcurrencyMode = cls.getAnnotation(EntityConcurrencyMode.class);
|
||||
if (entityConcurrencyMode != null) {
|
||||
descriptor.setConcurrencyMode(entityConcurrencyMode.value());
|
||||
}
|
||||
}
|
||||
|
||||
private void readCacheStrategy(CacheStrategy cacheStrategy, CacheTuning cacheTuning) {
|
||||
|
||||
CacheOptions cacheOptions = descriptor.getCacheOptions();
|
||||
if (cacheTuning != null) {
|
||||
cacheOptions.setMaxSecsToLive(cacheTuning.maxSecsToLive());
|
||||
cacheOptions.setMaxIdleSecs(cacheTuning.maxIdleSecs());
|
||||
}
|
||||
if (cacheStrategy != null) {
|
||||
cacheOptions.setUseCache(cacheStrategy.useBeanCache());
|
||||
cacheOptions.setReadOnly(cacheStrategy.readOnly());
|
||||
cacheOptions.setWarmingQuery(cacheStrategy.warmingQuery());
|
||||
if (cacheStrategy.naturalKey().length() > 0) {
|
||||
String propName = cacheStrategy.naturalKey().trim();
|
||||
DeployBeanProperty beanProperty = descriptor.getBeanProperty(propName);
|
||||
if (beanProperty != null) {
|
||||
beanProperty.setNaturalKey(true);
|
||||
cacheOptions.setNaturalKey(propName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readNamedQueries(NamedQueries namedQueries) {
|
||||
NamedQuery[] queries = namedQueries.value();
|
||||
for (int i = 0; i < queries.length; i++) {
|
||||
readNamedQuery(queries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void readNamedQuery(NamedQuery namedQuery) {
|
||||
DeployNamedQuery q = new DeployNamedQuery(namedQuery);
|
||||
descriptor.add(q);
|
||||
}
|
||||
|
||||
private void readNamedUpdates(NamedUpdates updates) {
|
||||
NamedUpdate[] updateArray = updates.value();
|
||||
for (int i = 0; i < updateArray.length; i++) {
|
||||
readNamedUpdate(updateArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void readNamedUpdate(NamedUpdate update) {
|
||||
DeployNamedUpdate upd = new DeployNamedUpdate(update);
|
||||
descriptor.add(upd);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.annotation.CacheTuning;
|
||||
import com.avaje.ebean.annotation.EntityConcurrencyMode;
|
||||
import com.avaje.ebean.annotation.NamedUpdate;
|
||||
import com.avaje.ebean.annotation.NamedUpdates;
|
||||
import com.avaje.ebean.annotation.UpdateMode;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
/**
|
||||
* Read the class level deployment annotations.
|
||||
*/
|
||||
public class AnnotationClass extends AnnotationParser {
|
||||
|
||||
public AnnotationClass(DeployBeanInfo<?> info) {
|
||||
super(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the class level deployment annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
read(descriptor.getBeanType());
|
||||
setTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table name if it has not already been set.
|
||||
*/
|
||||
private void setTableName() {
|
||||
|
||||
if (descriptor.isBaseTableType()) {
|
||||
|
||||
// default the TableName using NamingConvention.
|
||||
TableName tableName = namingConvention.getTableName(descriptor.getBeanType());
|
||||
|
||||
descriptor.setBaseTable(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
private void read(Class<?> cls) {
|
||||
|
||||
Entity entity = cls.getAnnotation(Entity.class);
|
||||
if (entity != null) {
|
||||
if (entity.name().equals("")) {
|
||||
descriptor.setName(cls.getSimpleName());
|
||||
} else {
|
||||
descriptor.setName(entity.name());
|
||||
}
|
||||
}
|
||||
|
||||
Embeddable embeddable = cls.getAnnotation(Embeddable.class);
|
||||
if (embeddable != null) {
|
||||
descriptor.setEntityType(EntityType.EMBEDDED);
|
||||
descriptor.setName("Embeddable:" + cls.getSimpleName());
|
||||
}
|
||||
|
||||
UniqueConstraint uc = cls.getAnnotation(UniqueConstraint.class);
|
||||
if (uc != null) {
|
||||
descriptor.addCompoundUniqueConstraint(new CompoundUniqueContraint(uc.columnNames()));
|
||||
}
|
||||
|
||||
Table table = cls.getAnnotation(Table.class);
|
||||
if (table != null) {
|
||||
UniqueConstraint[] uniqueConstraints = table.uniqueConstraints();
|
||||
if (uniqueConstraints != null) {
|
||||
for (UniqueConstraint c : uniqueConstraints) {
|
||||
descriptor.addCompoundUniqueConstraint(new CompoundUniqueContraint(c.columnNames()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMode updateMode = cls.getAnnotation(UpdateMode.class);
|
||||
if (updateMode != null) {
|
||||
descriptor.setUpdateChangesOnly(updateMode.updateChangesOnly());
|
||||
}
|
||||
|
||||
NamedQueries namedQueries = cls.getAnnotation(NamedQueries.class);
|
||||
if (namedQueries != null) {
|
||||
readNamedQueries(namedQueries);
|
||||
}
|
||||
NamedQuery namedQuery = cls.getAnnotation(NamedQuery.class);
|
||||
if (namedQuery != null) {
|
||||
readNamedQuery(namedQuery);
|
||||
}
|
||||
|
||||
NamedUpdates namedUpdates = cls.getAnnotation(NamedUpdates.class);
|
||||
if (namedUpdates != null) {
|
||||
readNamedUpdates(namedUpdates);
|
||||
}
|
||||
|
||||
NamedUpdate namedUpdate = cls.getAnnotation(NamedUpdate.class);
|
||||
if (namedUpdate != null) {
|
||||
readNamedUpdate(namedUpdate);
|
||||
}
|
||||
|
||||
CacheStrategy cacheStrategy = cls.getAnnotation(CacheStrategy.class);
|
||||
CacheTuning cacheTuning = cls.getAnnotation(CacheTuning.class);
|
||||
if (cacheStrategy != null || cacheTuning != null) {
|
||||
readCacheStrategy(cacheStrategy, cacheTuning);
|
||||
}
|
||||
|
||||
EntityConcurrencyMode entityConcurrencyMode = cls.getAnnotation(EntityConcurrencyMode.class);
|
||||
if (entityConcurrencyMode != null) {
|
||||
descriptor.setConcurrencyMode(entityConcurrencyMode.value());
|
||||
}
|
||||
}
|
||||
|
||||
private void readCacheStrategy(CacheStrategy cacheStrategy, CacheTuning cacheTuning) {
|
||||
|
||||
CacheOptions cacheOptions = descriptor.getCacheOptions();
|
||||
if (cacheTuning != null) {
|
||||
cacheOptions.setMaxSecsToLive(cacheTuning.maxSecsToLive());
|
||||
cacheOptions.setMaxIdleSecs(cacheTuning.maxIdleSecs());
|
||||
}
|
||||
if (cacheStrategy != null) {
|
||||
cacheOptions.setUseCache(cacheStrategy.useBeanCache());
|
||||
cacheOptions.setReadOnly(cacheStrategy.readOnly());
|
||||
cacheOptions.setWarmingQuery(cacheStrategy.warmingQuery());
|
||||
if (cacheStrategy.naturalKey().length() > 0) {
|
||||
String propName = cacheStrategy.naturalKey().trim();
|
||||
DeployBeanProperty beanProperty = descriptor.getBeanProperty(propName);
|
||||
if (beanProperty != null) {
|
||||
beanProperty.setNaturalKey(true);
|
||||
cacheOptions.setNaturalKey(propName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readNamedQueries(NamedQueries namedQueries) {
|
||||
NamedQuery[] queries = namedQueries.value();
|
||||
for (int i = 0; i < queries.length; i++) {
|
||||
readNamedQuery(queries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void readNamedQuery(NamedQuery namedQuery) {
|
||||
DeployNamedQuery q = new DeployNamedQuery(namedQuery);
|
||||
descriptor.add(q);
|
||||
}
|
||||
|
||||
private void readNamedUpdates(NamedUpdates updates) {
|
||||
NamedUpdate[] updateArray = updates.value();
|
||||
for (int i = 0; i < updateArray.length; i++) {
|
||||
readNamedUpdate(updateArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void readNamedUpdate(NamedUpdate update) {
|
||||
DeployNamedUpdate upd = new DeployNamedUpdate(update);
|
||||
descriptor.add(upd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,427 +1,427 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.annotation.*;
|
||||
import com.avaje.ebean.config.EncryptDeploy;
|
||||
import com.avaje.ebean.config.EncryptDeploy.Mode;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.type.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Read the field level deployment annotations.
|
||||
*/
|
||||
public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
/**
|
||||
* By default we lazy load Lob properties.
|
||||
*/
|
||||
private FetchType defaultLobFetchType = FetchType.LAZY;
|
||||
|
||||
private GeneratedPropertyFactory generatedPropFactory = new GeneratedPropertyFactory();
|
||||
|
||||
public AnnotationFields(DeployBeanInfo<?> info, boolean eagerFetchLobs) {
|
||||
super(info);
|
||||
|
||||
if (eagerFetchLobs) {
|
||||
defaultLobFetchType = FetchType.EAGER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the field level deployment annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
|
||||
for (DeployBeanProperty prop : descriptor.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?>) {
|
||||
readAssocOne(prop);
|
||||
} else {
|
||||
readField(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the Id marker annotations on EmbeddedId properties.
|
||||
*/
|
||||
private void readAssocOne(DeployBeanProperty prop) {
|
||||
|
||||
Id id = get(prop, Id.class);
|
||||
if (id != null) {
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
EmbeddedId embeddedId = get(prop, EmbeddedId.class);
|
||||
if (embeddedId != null) {
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
prop.setEmbedded(true);
|
||||
}
|
||||
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
if (prop.isId() && !prop.isEmbedded()) {
|
||||
prop.setEmbedded(true);
|
||||
}
|
||||
readEmbeddedAttributeOverrides((DeployBeanPropertyAssocOne<?>) prop);
|
||||
}
|
||||
}
|
||||
|
||||
private void readField(DeployBeanProperty prop) {
|
||||
|
||||
// all Enums will have a ScalarType assigned...
|
||||
boolean isEnum = prop.getPropertyType().isEnum();
|
||||
Enumerated enumerated = get(prop, Enumerated.class);
|
||||
if (isEnum || enumerated != null) {
|
||||
util.setEnumScalarType(enumerated, prop);
|
||||
}
|
||||
|
||||
// its persistent and assumed to be on the base table
|
||||
// rather than on a secondary table
|
||||
prop.setDbRead(true);
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
|
||||
Column column = get(prop, Column.class);
|
||||
if (column != null) {
|
||||
readColumn(column, prop);
|
||||
}
|
||||
Expose expose = get(prop, Expose.class);
|
||||
if (expose != null) {
|
||||
prop.setExposeSerialize(expose.serialize());
|
||||
prop.setExposeDeserialize(expose.deserialize());
|
||||
}
|
||||
|
||||
if (prop.getDbColumn() == null) {
|
||||
// No @Column annotation or @Column.name() not set
|
||||
// Use the NamingConvention to set the DB column name
|
||||
String dbColumn = namingConvention.getColumnFromProperty(beanType, prop.getName());
|
||||
prop.setDbColumn(dbColumn);
|
||||
}
|
||||
|
||||
GeneratedValue gen = get(prop, GeneratedValue.class);
|
||||
if (gen != null) {
|
||||
readGenValue(gen, prop);
|
||||
}
|
||||
|
||||
Id id = (Id) get(prop, Id.class);
|
||||
if (id != null) {
|
||||
readId(id, prop);
|
||||
}
|
||||
|
||||
// determine the JDBC type using Lob/Temporal
|
||||
// otherwise based on the property Class
|
||||
Lob lob = get(prop, Lob.class);
|
||||
Temporal temporal = get(prop, Temporal.class);
|
||||
if (temporal != null) {
|
||||
readTemporal(temporal, prop);
|
||||
|
||||
} else if (lob != null) {
|
||||
util.setLobType(prop);
|
||||
}
|
||||
|
||||
Formula formula = get(prop, Formula.class);
|
||||
if (formula != null) {
|
||||
prop.setSqlFormula(formula.select(), formula.join());
|
||||
}
|
||||
|
||||
Version version = get(prop, Version.class);
|
||||
if (version != null) {
|
||||
// explicitly specify a version column
|
||||
prop.setVersionColumn(true);
|
||||
generatedPropFactory.setVersion(prop);
|
||||
}
|
||||
|
||||
Basic basic = get(prop, Basic.class);
|
||||
if (basic != null) {
|
||||
prop.setFetchType(basic.fetch());
|
||||
if (!basic.optional()) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
} else if (prop.isLob()) {
|
||||
// use the default Lob fetchType
|
||||
prop.setFetchType(defaultLobFetchType);
|
||||
}
|
||||
|
||||
CreatedTimestamp ct = get(prop, CreatedTimestamp.class);
|
||||
if (ct != null) {
|
||||
generatedPropFactory.setInsertTimestamp(prop);
|
||||
}
|
||||
|
||||
UpdatedTimestamp ut = get(prop, UpdatedTimestamp.class);
|
||||
if (ut != null) {
|
||||
generatedPropFactory.setUpdateTimestamp(prop);
|
||||
}
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isNotNullOnAllValidationGroups(notNull.groups())) {
|
||||
// Not null on all validation groups so enable
|
||||
// DDL generation of Not Null Constraint
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
Size size = get(prop, Size.class);
|
||||
if (size != null) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
// explicitly specify a version column
|
||||
prop.setDbLength(size.max());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmbeddedColumns columns = get(prop, EmbeddedColumns.class);
|
||||
if (columns != null) {
|
||||
if (prop instanceof DeployBeanPropertyCompound) {
|
||||
DeployBeanPropertyCompound p = (DeployBeanPropertyCompound) prop;
|
||||
|
||||
// convert into a Map
|
||||
String propColumns = columns.columns();
|
||||
Map<String, String> propMap = StringHelper.delimitedToMap(propColumns, ",", "=");
|
||||
|
||||
p.getDeployEmbedded().putAll(propMap);
|
||||
|
||||
CtCompoundType<?> compoundType = p.getCompoundType();
|
||||
if (compoundType == null) {
|
||||
throw new RuntimeException("No registered CtCompoundType for " + p.getPropertyType());
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Can't use EmbeddedColumns on ScalarType "
|
||||
+ prop.getFullBeanName());
|
||||
}
|
||||
}
|
||||
|
||||
// Want to process last so we can use with @Formula
|
||||
Transient t = get(prop, Transient.class);
|
||||
if (t != null) {
|
||||
// it is not a persistent property.
|
||||
prop.setDbRead(false);
|
||||
prop.setDbInsertable(false);
|
||||
prop.setDbUpdateable(false);
|
||||
prop.setTransient(true);
|
||||
}
|
||||
|
||||
if (!prop.isTransient()) {
|
||||
|
||||
EncryptDeploy encryptDeploy = util.getEncryptDeploy(info.getDescriptor().getBaseTableFull(),
|
||||
prop.getDbColumn());
|
||||
if (encryptDeploy == null || encryptDeploy.getMode().equals(Mode.MODE_ANNOTATION)) {
|
||||
Encrypted encrypted = get(prop, Encrypted.class);
|
||||
if (encrypted != null) {
|
||||
setEncryption(prop, encrypted.dbEncryption(), encrypted.dbLength());
|
||||
}
|
||||
} else if (Mode.MODE_ENCRYPT.equals(encryptDeploy.getMode())) {
|
||||
setEncryption(prop, encryptDeploy.isDbEncrypt(), encryptDeploy.getDbLength());
|
||||
}
|
||||
}
|
||||
|
||||
Index index = get(prop, Index.class);
|
||||
if (index != null) {
|
||||
if(hasRelationshipItem(prop)) {
|
||||
throw new RuntimeException("Can't use Index on foreign key relationships.");
|
||||
}
|
||||
prop.setIndexed(true);
|
||||
prop.setIndexName(index.value());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRelationshipItem(DeployBeanProperty prop) {
|
||||
return get(prop, OneToMany.class) != null ||
|
||||
get(prop, ManyToOne.class) != null ||
|
||||
get(prop, OneToOne.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the validation is on all validation groups and hence
|
||||
* can be applied to DDL generation.
|
||||
*/
|
||||
private boolean isNotNullOnAllValidationGroups(Class<?>[] groups) {
|
||||
if (groups.length == 0) {
|
||||
return true;
|
||||
}
|
||||
if (groups.length == 1 && javax.validation.groups.Default.class.isAssignableFrom(groups[0])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setEncryption(DeployBeanProperty prop, boolean dbEncString, int dbLen) {
|
||||
|
||||
util.checkEncryptKeyManagerDefined(prop.getFullBeanName());
|
||||
|
||||
ScalarType<?> st = prop.getScalarType();
|
||||
if (byte[].class.equals(st.getType())) {
|
||||
// Always using Java client encryption rather than DB for encryption
|
||||
// of binary data (partially as this is not supported on all db's etc)
|
||||
// This could be reviewed at a later stage.
|
||||
ScalarTypeBytesBase baseType = (ScalarTypeBytesBase) st;
|
||||
DataEncryptSupport support = createDataEncryptSupport(prop);
|
||||
ScalarTypeBytesEncrypted encryptedScalarType = new ScalarTypeBytesEncrypted(baseType, support);
|
||||
prop.setScalarType(encryptedScalarType);
|
||||
prop.setLocalEncrypted(true);
|
||||
return;
|
||||
|
||||
}
|
||||
if (dbEncString) {
|
||||
|
||||
DbEncrypt dbEncrypt = util.getDbPlatform().getDbEncrypt();
|
||||
|
||||
if (dbEncrypt != null) {
|
||||
// check if we have a DB encryption function for this type
|
||||
int jdbcType = prop.getScalarType().getJdbcType();
|
||||
DbEncryptFunction dbEncryptFunction = dbEncrypt.getDbEncryptFunction(jdbcType);
|
||||
if (dbEncryptFunction != null) {
|
||||
// Use DB functions to encrypt and decrypt
|
||||
prop.setDbEncryptFunction(dbEncryptFunction, dbEncrypt, dbLen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prop.setScalarType(createScalarType(prop, st));
|
||||
prop.setLocalEncrypted(true);
|
||||
if (dbLen > 0) {
|
||||
prop.setDbLength(dbLen);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private ScalarTypeEncryptedWrapper<?> createScalarType(DeployBeanProperty prop, ScalarType<?> st) {
|
||||
|
||||
// Use Java Encryptor wrapping the logical scalar type
|
||||
DataEncryptSupport support = createDataEncryptSupport(prop);
|
||||
ScalarTypeBytesBase byteType = getDbEncryptType(prop);
|
||||
|
||||
return new ScalarTypeEncryptedWrapper(st, byteType, support);
|
||||
}
|
||||
|
||||
private ScalarTypeBytesBase getDbEncryptType(DeployBeanProperty prop) {
|
||||
int dbType = prop.isLob() ? Types.BLOB : Types.VARBINARY;
|
||||
return (ScalarTypeBytesBase) util.getTypeManager().getScalarType(dbType);
|
||||
}
|
||||
|
||||
private DataEncryptSupport createDataEncryptSupport(DeployBeanProperty prop) {
|
||||
|
||||
String table = info.getDescriptor().getBaseTable();
|
||||
String column = prop.getDbColumn();
|
||||
|
||||
return util.createDataEncryptSupport(table, column);
|
||||
}
|
||||
|
||||
private void readId(Id id, DeployBeanProperty prop) {
|
||||
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
|
||||
if (prop.getPropertyType().equals(UUID.class)) {
|
||||
// An Id of type UUID
|
||||
if (descriptor.getIdGeneratorName() == null) {
|
||||
// Without a generator explicitly specified
|
||||
// so will use the default one AUTO_UUID
|
||||
descriptor.setIdGeneratorName(UuidIdGenerator.AUTO_UUID);
|
||||
descriptor.setIdType(IdType.GENERATOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readGenValue(GeneratedValue gen, DeployBeanProperty prop) {
|
||||
|
||||
String genName = gen.generator();
|
||||
|
||||
SequenceGenerator sequenceGenerator = find(prop, SequenceGenerator.class);
|
||||
if (sequenceGenerator != null) {
|
||||
if (sequenceGenerator.name().equals(genName)) {
|
||||
genName = sequenceGenerator.sequenceName();
|
||||
}
|
||||
descriptor.setSequenceInitialValue(sequenceGenerator.initialValue());
|
||||
descriptor.setSequenceAllocationSize(sequenceGenerator.allocationSize());
|
||||
}
|
||||
|
||||
GenerationType strategy = gen.strategy();
|
||||
|
||||
if (strategy == GenerationType.IDENTITY) {
|
||||
descriptor.setIdType(IdType.IDENTITY);
|
||||
|
||||
} else if (strategy == GenerationType.SEQUENCE) {
|
||||
descriptor.setIdType(IdType.SEQUENCE);
|
||||
if (genName != null && genName.length() > 0) {
|
||||
descriptor.setIdGeneratorName(genName);
|
||||
}
|
||||
|
||||
} else if (strategy == GenerationType.AUTO) {
|
||||
if (prop.getPropertyType().equals(UUID.class)) {
|
||||
descriptor.setIdGeneratorName(UuidIdGenerator.AUTO_UUID);
|
||||
descriptor.setIdType(IdType.GENERATOR);
|
||||
|
||||
} else {
|
||||
// use DatabasePlatform defaults
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readTemporal(Temporal temporal, DeployBeanProperty prop) {
|
||||
|
||||
TemporalType type = temporal.value();
|
||||
if (type.equals(TemporalType.DATE)) {
|
||||
prop.setDbType(Types.DATE);
|
||||
|
||||
} else if (type.equals(TemporalType.TIMESTAMP)) {
|
||||
prop.setDbType(Types.TIMESTAMP);
|
||||
|
||||
} else if (type.equals(TemporalType.TIME)) {
|
||||
prop.setDbType(Types.TIME);
|
||||
|
||||
} else {
|
||||
throw new PersistenceException("Unhandled type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private void readColumn(Column columnAnn, DeployBeanProperty prop) {
|
||||
|
||||
if (!isEmpty(columnAnn.name())) {
|
||||
String dbColumn = databasePlatform.convertQuotedIdentifiers(columnAnn.name());
|
||||
prop.setDbColumn(dbColumn);
|
||||
}
|
||||
|
||||
prop.setDbInsertable(columnAnn.insertable());
|
||||
prop.setDbUpdateable(columnAnn.updatable());
|
||||
prop.setNullable(columnAnn.nullable());
|
||||
prop.setUnique(columnAnn.unique());
|
||||
if (columnAnn.precision() > 0) {
|
||||
prop.setDbLength(columnAnn.precision());
|
||||
} else if (columnAnn.length() != 255) {
|
||||
// set default 255 on DbTypeMap
|
||||
prop.setDbLength(columnAnn.length());
|
||||
}
|
||||
prop.setDbScale(columnAnn.scale());
|
||||
prop.setDbColumnDefn(columnAnn.columnDefinition());
|
||||
|
||||
String baseTable = descriptor.getBaseTable();
|
||||
String tableName = columnAnn.table();
|
||||
if (tableName.equals("") || tableName.equalsIgnoreCase(baseTable)) {
|
||||
// its a base table property...
|
||||
} else {
|
||||
// its on a secondary table...
|
||||
prop.setSecondaryTable(tableName);
|
||||
// DeployTableJoin tableJoin = info.getTableJoin(tableName);
|
||||
// tableJoin.addProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.annotation.*;
|
||||
import com.avaje.ebean.config.EncryptDeploy;
|
||||
import com.avaje.ebean.config.EncryptDeploy.Mode;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.type.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Read the field level deployment annotations.
|
||||
*/
|
||||
public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
/**
|
||||
* By default we lazy load Lob properties.
|
||||
*/
|
||||
private FetchType defaultLobFetchType = FetchType.LAZY;
|
||||
|
||||
private GeneratedPropertyFactory generatedPropFactory = new GeneratedPropertyFactory();
|
||||
|
||||
public AnnotationFields(DeployBeanInfo<?> info, boolean eagerFetchLobs) {
|
||||
super(info);
|
||||
|
||||
if (eagerFetchLobs) {
|
||||
defaultLobFetchType = FetchType.EAGER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the field level deployment annotations.
|
||||
*/
|
||||
public void parse() {
|
||||
|
||||
for (DeployBeanProperty prop : descriptor.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?>) {
|
||||
readAssocOne(prop);
|
||||
} else {
|
||||
readField(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the Id marker annotations on EmbeddedId properties.
|
||||
*/
|
||||
private void readAssocOne(DeployBeanProperty prop) {
|
||||
|
||||
Id id = get(prop, Id.class);
|
||||
if (id != null) {
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
EmbeddedId embeddedId = get(prop, EmbeddedId.class);
|
||||
if (embeddedId != null) {
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
prop.setEmbedded(true);
|
||||
}
|
||||
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
if (prop.isId() && !prop.isEmbedded()) {
|
||||
prop.setEmbedded(true);
|
||||
}
|
||||
readEmbeddedAttributeOverrides((DeployBeanPropertyAssocOne<?>) prop);
|
||||
}
|
||||
}
|
||||
|
||||
private void readField(DeployBeanProperty prop) {
|
||||
|
||||
// all Enums will have a ScalarType assigned...
|
||||
boolean isEnum = prop.getPropertyType().isEnum();
|
||||
Enumerated enumerated = get(prop, Enumerated.class);
|
||||
if (isEnum || enumerated != null) {
|
||||
util.setEnumScalarType(enumerated, prop);
|
||||
}
|
||||
|
||||
// its persistent and assumed to be on the base table
|
||||
// rather than on a secondary table
|
||||
prop.setDbRead(true);
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
|
||||
Column column = get(prop, Column.class);
|
||||
if (column != null) {
|
||||
readColumn(column, prop);
|
||||
}
|
||||
Expose expose = get(prop, Expose.class);
|
||||
if (expose != null) {
|
||||
prop.setExposeSerialize(expose.serialize());
|
||||
prop.setExposeDeserialize(expose.deserialize());
|
||||
}
|
||||
|
||||
if (prop.getDbColumn() == null) {
|
||||
// No @Column annotation or @Column.name() not set
|
||||
// Use the NamingConvention to set the DB column name
|
||||
String dbColumn = namingConvention.getColumnFromProperty(beanType, prop.getName());
|
||||
prop.setDbColumn(dbColumn);
|
||||
}
|
||||
|
||||
GeneratedValue gen = get(prop, GeneratedValue.class);
|
||||
if (gen != null) {
|
||||
readGenValue(gen, prop);
|
||||
}
|
||||
|
||||
Id id = (Id) get(prop, Id.class);
|
||||
if (id != null) {
|
||||
readId(id, prop);
|
||||
}
|
||||
|
||||
// determine the JDBC type using Lob/Temporal
|
||||
// otherwise based on the property Class
|
||||
Lob lob = get(prop, Lob.class);
|
||||
Temporal temporal = get(prop, Temporal.class);
|
||||
if (temporal != null) {
|
||||
readTemporal(temporal, prop);
|
||||
|
||||
} else if (lob != null) {
|
||||
util.setLobType(prop);
|
||||
}
|
||||
|
||||
Formula formula = get(prop, Formula.class);
|
||||
if (formula != null) {
|
||||
prop.setSqlFormula(formula.select(), formula.join());
|
||||
}
|
||||
|
||||
Version version = get(prop, Version.class);
|
||||
if (version != null) {
|
||||
// explicitly specify a version column
|
||||
prop.setVersionColumn(true);
|
||||
generatedPropFactory.setVersion(prop);
|
||||
}
|
||||
|
||||
Basic basic = get(prop, Basic.class);
|
||||
if (basic != null) {
|
||||
prop.setFetchType(basic.fetch());
|
||||
if (!basic.optional()) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
} else if (prop.isLob()) {
|
||||
// use the default Lob fetchType
|
||||
prop.setFetchType(defaultLobFetchType);
|
||||
}
|
||||
|
||||
CreatedTimestamp ct = get(prop, CreatedTimestamp.class);
|
||||
if (ct != null) {
|
||||
generatedPropFactory.setInsertTimestamp(prop);
|
||||
}
|
||||
|
||||
UpdatedTimestamp ut = get(prop, UpdatedTimestamp.class);
|
||||
if (ut != null) {
|
||||
generatedPropFactory.setUpdateTimestamp(prop);
|
||||
}
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isNotNullOnAllValidationGroups(notNull.groups())) {
|
||||
// Not null on all validation groups so enable
|
||||
// DDL generation of Not Null Constraint
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
Size size = get(prop, Size.class);
|
||||
if (size != null) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
// explicitly specify a version column
|
||||
prop.setDbLength(size.max());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmbeddedColumns columns = get(prop, EmbeddedColumns.class);
|
||||
if (columns != null) {
|
||||
if (prop instanceof DeployBeanPropertyCompound) {
|
||||
DeployBeanPropertyCompound p = (DeployBeanPropertyCompound) prop;
|
||||
|
||||
// convert into a Map
|
||||
String propColumns = columns.columns();
|
||||
Map<String, String> propMap = StringHelper.delimitedToMap(propColumns, ",", "=");
|
||||
|
||||
p.getDeployEmbedded().putAll(propMap);
|
||||
|
||||
CtCompoundType<?> compoundType = p.getCompoundType();
|
||||
if (compoundType == null) {
|
||||
throw new RuntimeException("No registered CtCompoundType for " + p.getPropertyType());
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Can't use EmbeddedColumns on ScalarType "
|
||||
+ prop.getFullBeanName());
|
||||
}
|
||||
}
|
||||
|
||||
// Want to process last so we can use with @Formula
|
||||
Transient t = get(prop, Transient.class);
|
||||
if (t != null) {
|
||||
// it is not a persistent property.
|
||||
prop.setDbRead(false);
|
||||
prop.setDbInsertable(false);
|
||||
prop.setDbUpdateable(false);
|
||||
prop.setTransient(true);
|
||||
}
|
||||
|
||||
if (!prop.isTransient()) {
|
||||
|
||||
EncryptDeploy encryptDeploy = util.getEncryptDeploy(info.getDescriptor().getBaseTableFull(),
|
||||
prop.getDbColumn());
|
||||
if (encryptDeploy == null || encryptDeploy.getMode().equals(Mode.MODE_ANNOTATION)) {
|
||||
Encrypted encrypted = get(prop, Encrypted.class);
|
||||
if (encrypted != null) {
|
||||
setEncryption(prop, encrypted.dbEncryption(), encrypted.dbLength());
|
||||
}
|
||||
} else if (Mode.MODE_ENCRYPT.equals(encryptDeploy.getMode())) {
|
||||
setEncryption(prop, encryptDeploy.isDbEncrypt(), encryptDeploy.getDbLength());
|
||||
}
|
||||
}
|
||||
|
||||
Index index = get(prop, Index.class);
|
||||
if (index != null) {
|
||||
if(hasRelationshipItem(prop)) {
|
||||
throw new RuntimeException("Can't use Index on foreign key relationships.");
|
||||
}
|
||||
prop.setIndexed(true);
|
||||
prop.setIndexName(index.value());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRelationshipItem(DeployBeanProperty prop) {
|
||||
return get(prop, OneToMany.class) != null ||
|
||||
get(prop, ManyToOne.class) != null ||
|
||||
get(prop, OneToOne.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the validation is on all validation groups and hence
|
||||
* can be applied to DDL generation.
|
||||
*/
|
||||
private boolean isNotNullOnAllValidationGroups(Class<?>[] groups) {
|
||||
if (groups.length == 0) {
|
||||
return true;
|
||||
}
|
||||
if (groups.length == 1 && javax.validation.groups.Default.class.isAssignableFrom(groups[0])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setEncryption(DeployBeanProperty prop, boolean dbEncString, int dbLen) {
|
||||
|
||||
util.checkEncryptKeyManagerDefined(prop.getFullBeanName());
|
||||
|
||||
ScalarType<?> st = prop.getScalarType();
|
||||
if (byte[].class.equals(st.getType())) {
|
||||
// Always using Java client encryption rather than DB for encryption
|
||||
// of binary data (partially as this is not supported on all db's etc)
|
||||
// This could be reviewed at a later stage.
|
||||
ScalarTypeBytesBase baseType = (ScalarTypeBytesBase) st;
|
||||
DataEncryptSupport support = createDataEncryptSupport(prop);
|
||||
ScalarTypeBytesEncrypted encryptedScalarType = new ScalarTypeBytesEncrypted(baseType, support);
|
||||
prop.setScalarType(encryptedScalarType);
|
||||
prop.setLocalEncrypted(true);
|
||||
return;
|
||||
|
||||
}
|
||||
if (dbEncString) {
|
||||
|
||||
DbEncrypt dbEncrypt = util.getDbPlatform().getDbEncrypt();
|
||||
|
||||
if (dbEncrypt != null) {
|
||||
// check if we have a DB encryption function for this type
|
||||
int jdbcType = prop.getScalarType().getJdbcType();
|
||||
DbEncryptFunction dbEncryptFunction = dbEncrypt.getDbEncryptFunction(jdbcType);
|
||||
if (dbEncryptFunction != null) {
|
||||
// Use DB functions to encrypt and decrypt
|
||||
prop.setDbEncryptFunction(dbEncryptFunction, dbEncrypt, dbLen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prop.setScalarType(createScalarType(prop, st));
|
||||
prop.setLocalEncrypted(true);
|
||||
if (dbLen > 0) {
|
||||
prop.setDbLength(dbLen);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private ScalarTypeEncryptedWrapper<?> createScalarType(DeployBeanProperty prop, ScalarType<?> st) {
|
||||
|
||||
// Use Java Encryptor wrapping the logical scalar type
|
||||
DataEncryptSupport support = createDataEncryptSupport(prop);
|
||||
ScalarTypeBytesBase byteType = getDbEncryptType(prop);
|
||||
|
||||
return new ScalarTypeEncryptedWrapper(st, byteType, support);
|
||||
}
|
||||
|
||||
private ScalarTypeBytesBase getDbEncryptType(DeployBeanProperty prop) {
|
||||
int dbType = prop.isLob() ? Types.BLOB : Types.VARBINARY;
|
||||
return (ScalarTypeBytesBase) util.getTypeManager().getScalarType(dbType);
|
||||
}
|
||||
|
||||
private DataEncryptSupport createDataEncryptSupport(DeployBeanProperty prop) {
|
||||
|
||||
String table = info.getDescriptor().getBaseTable();
|
||||
String column = prop.getDbColumn();
|
||||
|
||||
return util.createDataEncryptSupport(table, column);
|
||||
}
|
||||
|
||||
private void readId(Id id, DeployBeanProperty prop) {
|
||||
|
||||
prop.setId(true);
|
||||
prop.setNullable(false);
|
||||
|
||||
if (prop.getPropertyType().equals(UUID.class)) {
|
||||
// An Id of type UUID
|
||||
if (descriptor.getIdGeneratorName() == null) {
|
||||
// Without a generator explicitly specified
|
||||
// so will use the default one AUTO_UUID
|
||||
descriptor.setIdGeneratorName(UuidIdGenerator.AUTO_UUID);
|
||||
descriptor.setIdType(IdType.GENERATOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readGenValue(GeneratedValue gen, DeployBeanProperty prop) {
|
||||
|
||||
String genName = gen.generator();
|
||||
|
||||
SequenceGenerator sequenceGenerator = find(prop, SequenceGenerator.class);
|
||||
if (sequenceGenerator != null) {
|
||||
if (sequenceGenerator.name().equals(genName)) {
|
||||
genName = sequenceGenerator.sequenceName();
|
||||
}
|
||||
descriptor.setSequenceInitialValue(sequenceGenerator.initialValue());
|
||||
descriptor.setSequenceAllocationSize(sequenceGenerator.allocationSize());
|
||||
}
|
||||
|
||||
GenerationType strategy = gen.strategy();
|
||||
|
||||
if (strategy == GenerationType.IDENTITY) {
|
||||
descriptor.setIdType(IdType.IDENTITY);
|
||||
|
||||
} else if (strategy == GenerationType.SEQUENCE) {
|
||||
descriptor.setIdType(IdType.SEQUENCE);
|
||||
if (genName != null && genName.length() > 0) {
|
||||
descriptor.setIdGeneratorName(genName);
|
||||
}
|
||||
|
||||
} else if (strategy == GenerationType.AUTO) {
|
||||
if (prop.getPropertyType().equals(UUID.class)) {
|
||||
descriptor.setIdGeneratorName(UuidIdGenerator.AUTO_UUID);
|
||||
descriptor.setIdType(IdType.GENERATOR);
|
||||
|
||||
} else {
|
||||
// use DatabasePlatform defaults
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readTemporal(Temporal temporal, DeployBeanProperty prop) {
|
||||
|
||||
TemporalType type = temporal.value();
|
||||
if (type.equals(TemporalType.DATE)) {
|
||||
prop.setDbType(Types.DATE);
|
||||
|
||||
} else if (type.equals(TemporalType.TIMESTAMP)) {
|
||||
prop.setDbType(Types.TIMESTAMP);
|
||||
|
||||
} else if (type.equals(TemporalType.TIME)) {
|
||||
prop.setDbType(Types.TIME);
|
||||
|
||||
} else {
|
||||
throw new PersistenceException("Unhandled type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private void readColumn(Column columnAnn, DeployBeanProperty prop) {
|
||||
|
||||
if (!isEmpty(columnAnn.name())) {
|
||||
String dbColumn = databasePlatform.convertQuotedIdentifiers(columnAnn.name());
|
||||
prop.setDbColumn(dbColumn);
|
||||
}
|
||||
|
||||
prop.setDbInsertable(columnAnn.insertable());
|
||||
prop.setDbUpdateable(columnAnn.updatable());
|
||||
prop.setNullable(columnAnn.nullable());
|
||||
prop.setUnique(columnAnn.unique());
|
||||
if (columnAnn.precision() > 0) {
|
||||
prop.setDbLength(columnAnn.precision());
|
||||
} else if (columnAnn.length() != 255) {
|
||||
// set default 255 on DbTypeMap
|
||||
prop.setDbLength(columnAnn.length());
|
||||
}
|
||||
prop.setDbScale(columnAnn.scale());
|
||||
prop.setDbColumnDefn(columnAnn.columnDefinition());
|
||||
|
||||
String baseTable = descriptor.getBaseTable();
|
||||
String tableName = columnAnn.table();
|
||||
if (tableName.equals("") || tableName.equalsIgnoreCase(baseTable)) {
|
||||
// its a base table property...
|
||||
} else {
|
||||
// its on a secondary table...
|
||||
prop.setSecondaryTable(tableName);
|
||||
// DeployTableJoin tableJoin = info.getTableJoin(tableName);
|
||||
// tableJoin.addProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,77 +1,77 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.CascadeType;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Base class for reading deployment annotations.
|
||||
*/
|
||||
public abstract class AnnotationParser extends AnnotationBase {
|
||||
|
||||
protected final DeployBeanInfo<?> info;
|
||||
|
||||
protected final DeployBeanDescriptor<?> descriptor;
|
||||
|
||||
protected final Class<?> beanType;
|
||||
|
||||
protected boolean validationAnnotations;
|
||||
|
||||
public AnnotationParser(DeployBeanInfo<?> info) {
|
||||
super(info.getUtil());
|
||||
this.info = info;
|
||||
this.beanType = info.getDescriptor().getBeanType();
|
||||
this.descriptor = info.getDescriptor();
|
||||
|
||||
try {
|
||||
Class.forName("javax.validation.constraints.NotNull");
|
||||
validationAnnotations = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
// javax.validation not in the classpath so don't
|
||||
// check for NotNull and Size
|
||||
validationAnnotations = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read the deployment annotations.
|
||||
*/
|
||||
public abstract void parse();
|
||||
|
||||
/**
|
||||
* Helper method to set cascade types to the CascadeInfo on BeanProperty.
|
||||
*/
|
||||
protected void setCascadeTypes(CascadeType[] cascadeTypes, BeanCascadeInfo cascadeInfo) {
|
||||
if (cascadeTypes != null && cascadeTypes.length > 0) {
|
||||
cascadeInfo.setTypes(cascadeTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an AttributeOverrides if they exist for this embedded bean.
|
||||
*/
|
||||
protected void readEmbeddedAttributeOverrides(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
AttributeOverrides attrOverrides = get(prop, AttributeOverrides.class);
|
||||
if (attrOverrides != null) {
|
||||
HashMap<String, String> propMap = new HashMap<String, String>();
|
||||
AttributeOverride[] aoArray = attrOverrides.value();
|
||||
for (int i = 0; i < aoArray.length; i++) {
|
||||
String propName = aoArray[i].name();
|
||||
String columnName = aoArray[i].column().name();
|
||||
|
||||
propMap.put(propName, columnName);
|
||||
}
|
||||
|
||||
prop.getDeployEmbedded().putAll(propMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.CascadeType;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Base class for reading deployment annotations.
|
||||
*/
|
||||
public abstract class AnnotationParser extends AnnotationBase {
|
||||
|
||||
protected final DeployBeanInfo<?> info;
|
||||
|
||||
protected final DeployBeanDescriptor<?> descriptor;
|
||||
|
||||
protected final Class<?> beanType;
|
||||
|
||||
protected boolean validationAnnotations;
|
||||
|
||||
public AnnotationParser(DeployBeanInfo<?> info) {
|
||||
super(info.getUtil());
|
||||
this.info = info;
|
||||
this.beanType = info.getDescriptor().getBeanType();
|
||||
this.descriptor = info.getDescriptor();
|
||||
|
||||
try {
|
||||
Class.forName("javax.validation.constraints.NotNull");
|
||||
validationAnnotations = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
// javax.validation not in the classpath so don't
|
||||
// check for NotNull and Size
|
||||
validationAnnotations = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read the deployment annotations.
|
||||
*/
|
||||
public abstract void parse();
|
||||
|
||||
/**
|
||||
* Helper method to set cascade types to the CascadeInfo on BeanProperty.
|
||||
*/
|
||||
protected void setCascadeTypes(CascadeType[] cascadeTypes, BeanCascadeInfo cascadeInfo) {
|
||||
if (cascadeTypes != null && cascadeTypes.length > 0) {
|
||||
cascadeInfo.setTypes(cascadeTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an AttributeOverrides if they exist for this embedded bean.
|
||||
*/
|
||||
protected void readEmbeddedAttributeOverrides(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
AttributeOverrides attrOverrides = get(prop, AttributeOverrides.class);
|
||||
if (attrOverrides != null) {
|
||||
HashMap<String, String> propMap = new HashMap<String, String>();
|
||||
AttributeOverride[] aoArray = attrOverrides.value();
|
||||
for (int i = 0; i < aoArray.length; i++) {
|
||||
String propName = aoArray[i].name();
|
||||
String columnName = aoArray[i].column().name();
|
||||
|
||||
propMap.put(propName, columnName);
|
||||
}
|
||||
|
||||
prop.getDeployEmbedded().putAll(propMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.annotation.Sql;
|
||||
import com.avaje.ebean.annotation.SqlSelect;
|
||||
import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta;
|
||||
|
||||
/**
|
||||
* Read the class level deployment annotations.
|
||||
*/
|
||||
public class AnnotationSql extends AnnotationParser {
|
||||
|
||||
public AnnotationSql(DeployBeanInfo<?> info) {
|
||||
super(info);
|
||||
}
|
||||
|
||||
public void parse() {
|
||||
Class<?> cls = descriptor.getBeanType();
|
||||
Sql sql = cls.getAnnotation(Sql.class);
|
||||
if (sql != null) {
|
||||
setSql(sql);
|
||||
}
|
||||
|
||||
SqlSelect sqlSelect = cls.getAnnotation(SqlSelect.class);
|
||||
if (sqlSelect != null) {
|
||||
setSqlSelect(sqlSelect);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSql(Sql sql) {
|
||||
SqlSelect[] select = sql.select();
|
||||
for (int i = 0; i < select.length; i++) {
|
||||
setSqlSelect(select[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSqlSelect(SqlSelect sqlSelect) {
|
||||
|
||||
DRawSqlMeta rawSqlMeta = new DRawSqlMeta(sqlSelect);
|
||||
descriptor.add(rawSqlMeta);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.annotation.Sql;
|
||||
import com.avaje.ebean.annotation.SqlSelect;
|
||||
import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta;
|
||||
|
||||
/**
|
||||
* Read the class level deployment annotations.
|
||||
*/
|
||||
public class AnnotationSql extends AnnotationParser {
|
||||
|
||||
public AnnotationSql(DeployBeanInfo<?> info) {
|
||||
super(info);
|
||||
}
|
||||
|
||||
public void parse() {
|
||||
Class<?> cls = descriptor.getBeanType();
|
||||
Sql sql = cls.getAnnotation(Sql.class);
|
||||
if (sql != null) {
|
||||
setSql(sql);
|
||||
}
|
||||
|
||||
SqlSelect sqlSelect = cls.getAnnotation(SqlSelect.class);
|
||||
if (sqlSelect != null) {
|
||||
setSqlSelect(sqlSelect);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSql(Sql sql) {
|
||||
SqlSelect[] select = sql.select();
|
||||
for (int i = 0; i < select.length; i++) {
|
||||
setSqlSelect(select[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSqlSelect(SqlSelect sqlSelect) {
|
||||
|
||||
DRawSqlMeta rawSqlMeta = new DRawSqlMeta(sqlSelect);
|
||||
descriptor.add(rawSqlMeta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Wraps information about a bean during deployment parsing.
|
||||
*/
|
||||
public class DeployBeanInfo<T> {
|
||||
|
||||
/**
|
||||
* Holds TableJoins for secondary table properties.
|
||||
*/
|
||||
private final HashMap<String,DeployTableJoin> tableJoinMap = new HashMap<String, DeployTableJoin>();
|
||||
|
||||
private final DeployUtil util;
|
||||
|
||||
private final DeployBeanDescriptor<T> descriptor;
|
||||
|
||||
/**
|
||||
* Create with a DeployUtil and BeanDescriptor.
|
||||
*/
|
||||
public DeployBeanInfo(DeployUtil util, DeployBeanDescriptor<T> descriptor) {
|
||||
this.util = util;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ""+descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor currently being processed.
|
||||
*/
|
||||
public DeployBeanDescriptor<T> getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DeployUtil we are using.
|
||||
*/
|
||||
public DeployUtil getUtil() {
|
||||
return util;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appropriate TableJoin for a property mapped to a secondary table.
|
||||
*/
|
||||
public DeployTableJoin getTableJoin(String tableName) {
|
||||
|
||||
String key = tableName.toLowerCase();
|
||||
|
||||
DeployTableJoin tableJoin = (DeployTableJoin) tableJoinMap.get(key);
|
||||
if (tableJoin == null) {
|
||||
tableJoin = new DeployTableJoin();
|
||||
tableJoin.setTable(tableName);
|
||||
tableJoin.setType(SqlJoinType.INNER);
|
||||
descriptor.addTableJoin(tableJoin);
|
||||
|
||||
tableJoinMap.put(key, tableJoin);
|
||||
}
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a the join alias for a assoc one property.
|
||||
*/
|
||||
public void setBeanJoinType(DeployBeanPropertyAssocOne<?> beanProp, boolean outerJoin) {
|
||||
|
||||
DeployTableJoin tableJoin = beanProp.getTableJoin();
|
||||
tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Wraps information about a bean during deployment parsing.
|
||||
*/
|
||||
public class DeployBeanInfo<T> {
|
||||
|
||||
/**
|
||||
* Holds TableJoins for secondary table properties.
|
||||
*/
|
||||
private final HashMap<String,DeployTableJoin> tableJoinMap = new HashMap<String, DeployTableJoin>();
|
||||
|
||||
private final DeployUtil util;
|
||||
|
||||
private final DeployBeanDescriptor<T> descriptor;
|
||||
|
||||
/**
|
||||
* Create with a DeployUtil and BeanDescriptor.
|
||||
*/
|
||||
public DeployBeanInfo(DeployUtil util, DeployBeanDescriptor<T> descriptor) {
|
||||
this.util = util;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ""+descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor currently being processed.
|
||||
*/
|
||||
public DeployBeanDescriptor<T> getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DeployUtil we are using.
|
||||
*/
|
||||
public DeployUtil getUtil() {
|
||||
return util;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appropriate TableJoin for a property mapped to a secondary table.
|
||||
*/
|
||||
public DeployTableJoin getTableJoin(String tableName) {
|
||||
|
||||
String key = tableName.toLowerCase();
|
||||
|
||||
DeployTableJoin tableJoin = (DeployTableJoin) tableJoinMap.get(key);
|
||||
if (tableJoin == null) {
|
||||
tableJoin = new DeployTableJoin();
|
||||
tableJoin.setTable(tableName);
|
||||
tableJoin.setType(SqlJoinType.INNER);
|
||||
descriptor.addTableJoin(tableJoin);
|
||||
|
||||
tableJoinMap.put(key, tableJoin);
|
||||
}
|
||||
return tableJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a the join alias for a assoc one property.
|
||||
*/
|
||||
public void setBeanJoinType(DeployBeanPropertyAssocOne<?> beanProp, boolean outerJoin) {
|
||||
|
||||
DeployTableJoin tableJoin = beanProp.getTableJoin();
|
||||
tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+427
-427
@@ -1,427 +1,427 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.ColumnHstore;
|
||||
import com.avaje.ebeaninternal.server.core.Message;
|
||||
import com.avaje.ebeaninternal.server.deploy.DetermineManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypePostgresHstore;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
|
||||
|
||||
/**
|
||||
* Create the properties for a bean.
|
||||
* <p>
|
||||
* This also needs to determine if the property is a associated many, associated
|
||||
* one or normal scalar property.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployCreateProperties {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployCreateProperties.class);
|
||||
|
||||
private final DetermineManyType determineManyType;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
public DeployCreateProperties(TypeManager typeManager) {
|
||||
this.typeManager = typeManager;
|
||||
this.determineManyType = new DetermineManyType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the appropriate properties for a bean.
|
||||
*/
|
||||
public void createProperties(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
createProperties(desc, desc.getBeanType(), 0);
|
||||
desc.sortProperties();
|
||||
|
||||
// check the transient properties...
|
||||
for (DeployBeanProperty prop : desc.propertiesAll()) {
|
||||
if (prop.isTransient()) {
|
||||
if (prop.getWriteMethod() == null || prop.getReadMethod() == null) {
|
||||
// Typically a helper method ... this is expected
|
||||
logger.trace("... transient: " + prop.getFullBeanName());
|
||||
} else {
|
||||
// dubious, possible error...
|
||||
String msg = Message.msg("deploy.property.nofield", desc.getFullName(), prop.getName());
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should ignore this field.
|
||||
* <p>
|
||||
* We want to ignore ebean internal fields and some others as well.
|
||||
* </p>
|
||||
*/
|
||||
private boolean ignoreFieldByName(String fieldName) {
|
||||
if (fieldName.startsWith("_ebean_")) {
|
||||
// ignore Ebean internal fields
|
||||
return true;
|
||||
}
|
||||
if (fieldName.startsWith("ajc$instance$")) {
|
||||
// ignore AspectJ internal fields
|
||||
return true;
|
||||
}
|
||||
|
||||
// we are interested in this field
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* properties the bean properties from Class. Some of these properties may not map to database
|
||||
* columns.
|
||||
*/
|
||||
private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, int level) {
|
||||
|
||||
boolean scalaObject = desc.isScalaObject();
|
||||
|
||||
try {
|
||||
Method[] declaredMethods = beanType.getDeclaredMethods();
|
||||
Field[] fields = beanType.getDeclaredFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
|
||||
Field field = fields[i];
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
// not interested in static fields
|
||||
|
||||
} else if (Modifier.isTransient(field.getModifiers())) {
|
||||
// not interested in transient fields
|
||||
logger.trace("Skipping transient field " + field.getName() + " in " + beanType.getName());
|
||||
|
||||
} else if (ignoreFieldByName(field.getName())) {
|
||||
// not interested this field (ebean or aspectJ field)
|
||||
|
||||
} else {
|
||||
|
||||
String fieldName = getFieldName(field, beanType);
|
||||
String initFieldName = initCap(fieldName);
|
||||
|
||||
Method getter = findGetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
Method setter = findSetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field, beanType, getter, setter);
|
||||
if (prop == null) {
|
||||
// transient annotation on unsupported type
|
||||
|
||||
} else {
|
||||
// set a order that gives priority to inherited properties
|
||||
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
|
||||
int sortOverride = prop.getSortOverride();
|
||||
prop.setSortOrder((level * 10000 + 100 - i + sortOverride));
|
||||
|
||||
DeployBeanProperty replaced = desc.addBeanProperty(prop);
|
||||
if (replaced != null) {
|
||||
if (replaced.isTransient()) {
|
||||
// expected for inheritance...
|
||||
} else {
|
||||
String msg = "Huh??? property " + prop.getFullBeanName() + " being defined twice";
|
||||
msg += " but replaced property was not transient? This is not expected?";
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> superClass = beanType.getSuperclass();
|
||||
|
||||
if (!superClass.equals(Object.class)) {
|
||||
// recursively add any properties in the inheritance hierarchy
|
||||
// up to the Object.class level...
|
||||
createProperties(desc, superClass, level + 1);
|
||||
}
|
||||
|
||||
} catch (PersistenceException ex) {
|
||||
throw ex;
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the first letter of the string upper case.
|
||||
*/
|
||||
private String initCap(String str) {
|
||||
if (str.length() > 1) {
|
||||
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
|
||||
} else {
|
||||
// only a single char
|
||||
return str.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean spec field name (trim of "is" from boolean types)
|
||||
*/
|
||||
private String getFieldName(Field field, Class<?> beanType) {
|
||||
|
||||
String name = field.getName();
|
||||
|
||||
if ((Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType())) && name.startsWith("is")
|
||||
&& name.length() > 2) {
|
||||
|
||||
// it is a boolean type field starting with "is"
|
||||
char c = name.charAt(2);
|
||||
if (Character.isUpperCase(c)) {
|
||||
String msg = "trimming off 'is' from boolean field name " + name + " in class " + beanType.getName();
|
||||
logger.info(msg);
|
||||
|
||||
return name.substring(2);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static getter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findGetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject) {
|
||||
|
||||
String methGetName = "get" + initFieldName;
|
||||
String methIsName = "is" + initFieldName;
|
||||
String scalaGet = field.getName();
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
if ((scalaObject && m.getName().equals(scalaGet)) || m.getName().equals(methGetName)
|
||||
|| m.getName().equals(methIsName)) {
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 0) {
|
||||
if (field.getType().equals(m.getReturnType())) {
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
// we find it...
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static setter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findSetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject) {
|
||||
|
||||
String methSetName = "set" + initFieldName;
|
||||
String scalaSetName = field.getName() + "_$eq";
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
|
||||
if ((scalaObject && m.getName().equals(scalaSetName)) || m.getName().equals(methSetName)) {
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 1 && field.getType().equals(params[0])) {
|
||||
if (void.class.equals(m.getReturnType())) {
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?> targetType, ManyType manyType) {
|
||||
|
||||
try {
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(targetType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, manyType);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("expected non-scalar type" + e.getMessage());
|
||||
}
|
||||
// TODO: Handle Collection of CompoundType and Embedded Type
|
||||
return new DeployBeanPropertyAssocMany(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
|
||||
|
||||
Class<?> propertyType = field.getType();
|
||||
|
||||
ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
|
||||
|
||||
if (manyToOne != null){
|
||||
Class<?> tt = manyToOne.targetEntity();
|
||||
|
||||
if (tt != null && !tt.equals(void.class)){
|
||||
propertyType = tt;
|
||||
logger.debug("target type" + tt);
|
||||
}
|
||||
}
|
||||
Class<?> innerType = propertyType;
|
||||
|
||||
String specialTypeKey = getSpecialScalarType(field);
|
||||
if (specialTypeKey != null) {
|
||||
ScalarType<?> scalarType = typeManager.getScalarTypeFromKey(specialTypeKey);
|
||||
if (scalarType == null) {
|
||||
logger.error("Could not find ScalarType to match key ["+specialTypeKey+"]");
|
||||
} else {
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
}
|
||||
|
||||
// check for Collection type (list, set or map)
|
||||
ManyType manyType = determineManyType.getManyType(propertyType);
|
||||
|
||||
if (manyType != null) {
|
||||
// List, Set or Map based object
|
||||
Class<?> targetType = determineTargetType(field);
|
||||
if (targetType == null) {
|
||||
Transient transAnnotation = field.getAnnotation(Transient.class);
|
||||
if (transAnnotation != null) {
|
||||
// not supporting this field (generic type used)
|
||||
return null;
|
||||
}
|
||||
logger.warn("Could not find parameter type (via reflection) on " + desc.getFullName() + " " + field.getName());
|
||||
}
|
||||
return createManyType(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
if (innerType.isEnum() || innerType.isPrimitive()) {
|
||||
return new DeployBeanProperty(desc, propertyType, null, null);
|
||||
}
|
||||
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(innerType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
|
||||
CtCompoundType<?> compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
if (isTransientField(field)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(innerType);
|
||||
if (checkImmutable.isImmutable()) {
|
||||
if (checkImmutable.isCompoundType()) {
|
||||
// use reflection to support compound immutable value objects
|
||||
typeManager.recursiveCreateScalarDataReader(innerType);
|
||||
compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
} else {
|
||||
// use reflection to support simple immutable value objects
|
||||
scalarType = typeManager.recursiveCreateScalarTypes(innerType);
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
}
|
||||
|
||||
return new DeployBeanPropertyAssocOne(desc, propertyType);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error with " + desc + " field:" + field.getName(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getSpecialScalarType(Field field) {
|
||||
|
||||
if (field.getAnnotation(ColumnHstore.class) != null) {
|
||||
return ScalarTypePostgresHstore.KEY;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isTransientField(Field field) {
|
||||
|
||||
Transient t = field.getAnnotation(Transient.class);
|
||||
return (t != null);
|
||||
}
|
||||
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType,
|
||||
Method getter, Method setter) {
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field);
|
||||
if (prop == null) {
|
||||
// transient annotation on unsupported type
|
||||
return null;
|
||||
} else {
|
||||
prop.setOwningType(beanType);
|
||||
prop.setName(field.getName());
|
||||
|
||||
// the getter or setter could be null if we are using
|
||||
// javaagent type enhancement. If we are using subclass
|
||||
// generation then we do need to find the getter and setter
|
||||
prop.setReadMethod(getter);
|
||||
prop.setWriteMethod(setter);
|
||||
prop.setField(field);
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the type of the List,Set or Map. Not been set explicitly so determine this from
|
||||
* ParameterizedType.
|
||||
*/
|
||||
private Class<?> determineTargetType(Field field) {
|
||||
|
||||
Type genType = field.getGenericType();
|
||||
if (genType instanceof ParameterizedType) {
|
||||
ParameterizedType ptype = (ParameterizedType) genType;
|
||||
|
||||
Type[] typeArgs = ptype.getActualTypeArguments();
|
||||
if (typeArgs.length == 1) {
|
||||
// probably a Set or List
|
||||
if (typeArgs[0] instanceof Class<?>) {
|
||||
return (Class<?>) typeArgs[0];
|
||||
}
|
||||
// throw new RuntimeException("Unexpected Parameterised Type? "+typeArgs[0]);
|
||||
return null;
|
||||
}
|
||||
if (typeArgs.length == 2) {
|
||||
// this is probably a Map
|
||||
if (typeArgs[1] instanceof ParameterizedType) {
|
||||
// not supporting ParameterizedType on Map.
|
||||
return null;
|
||||
}
|
||||
return (Class<?>) typeArgs[1];
|
||||
}
|
||||
}
|
||||
// if targetType is null, then must be set in annotations
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.ColumnHstore;
|
||||
import com.avaje.ebeaninternal.server.core.Message;
|
||||
import com.avaje.ebeaninternal.server.deploy.DetermineManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypePostgresHstore;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
|
||||
|
||||
/**
|
||||
* Create the properties for a bean.
|
||||
* <p>
|
||||
* This also needs to determine if the property is a associated many, associated
|
||||
* one or normal scalar property.
|
||||
* </p>
|
||||
*/
|
||||
public class DeployCreateProperties {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployCreateProperties.class);
|
||||
|
||||
private final DetermineManyType determineManyType;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
public DeployCreateProperties(TypeManager typeManager) {
|
||||
this.typeManager = typeManager;
|
||||
this.determineManyType = new DetermineManyType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the appropriate properties for a bean.
|
||||
*/
|
||||
public void createProperties(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
createProperties(desc, desc.getBeanType(), 0);
|
||||
desc.sortProperties();
|
||||
|
||||
// check the transient properties...
|
||||
for (DeployBeanProperty prop : desc.propertiesAll()) {
|
||||
if (prop.isTransient()) {
|
||||
if (prop.getWriteMethod() == null || prop.getReadMethod() == null) {
|
||||
// Typically a helper method ... this is expected
|
||||
logger.trace("... transient: " + prop.getFullBeanName());
|
||||
} else {
|
||||
// dubious, possible error...
|
||||
String msg = Message.msg("deploy.property.nofield", desc.getFullName(), prop.getName());
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should ignore this field.
|
||||
* <p>
|
||||
* We want to ignore ebean internal fields and some others as well.
|
||||
* </p>
|
||||
*/
|
||||
private boolean ignoreFieldByName(String fieldName) {
|
||||
if (fieldName.startsWith("_ebean_")) {
|
||||
// ignore Ebean internal fields
|
||||
return true;
|
||||
}
|
||||
if (fieldName.startsWith("ajc$instance$")) {
|
||||
// ignore AspectJ internal fields
|
||||
return true;
|
||||
}
|
||||
|
||||
// we are interested in this field
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* properties the bean properties from Class. Some of these properties may not map to database
|
||||
* columns.
|
||||
*/
|
||||
private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, int level) {
|
||||
|
||||
boolean scalaObject = desc.isScalaObject();
|
||||
|
||||
try {
|
||||
Method[] declaredMethods = beanType.getDeclaredMethods();
|
||||
Field[] fields = beanType.getDeclaredFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
|
||||
Field field = fields[i];
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
// not interested in static fields
|
||||
|
||||
} else if (Modifier.isTransient(field.getModifiers())) {
|
||||
// not interested in transient fields
|
||||
logger.trace("Skipping transient field " + field.getName() + " in " + beanType.getName());
|
||||
|
||||
} else if (ignoreFieldByName(field.getName())) {
|
||||
// not interested this field (ebean or aspectJ field)
|
||||
|
||||
} else {
|
||||
|
||||
String fieldName = getFieldName(field, beanType);
|
||||
String initFieldName = initCap(fieldName);
|
||||
|
||||
Method getter = findGetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
Method setter = findSetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field, beanType, getter, setter);
|
||||
if (prop == null) {
|
||||
// transient annotation on unsupported type
|
||||
|
||||
} else {
|
||||
// set a order that gives priority to inherited properties
|
||||
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
|
||||
int sortOverride = prop.getSortOverride();
|
||||
prop.setSortOrder((level * 10000 + 100 - i + sortOverride));
|
||||
|
||||
DeployBeanProperty replaced = desc.addBeanProperty(prop);
|
||||
if (replaced != null) {
|
||||
if (replaced.isTransient()) {
|
||||
// expected for inheritance...
|
||||
} else {
|
||||
String msg = "Huh??? property " + prop.getFullBeanName() + " being defined twice";
|
||||
msg += " but replaced property was not transient? This is not expected?";
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> superClass = beanType.getSuperclass();
|
||||
|
||||
if (!superClass.equals(Object.class)) {
|
||||
// recursively add any properties in the inheritance hierarchy
|
||||
// up to the Object.class level...
|
||||
createProperties(desc, superClass, level + 1);
|
||||
}
|
||||
|
||||
} catch (PersistenceException ex) {
|
||||
throw ex;
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the first letter of the string upper case.
|
||||
*/
|
||||
private String initCap(String str) {
|
||||
if (str.length() > 1) {
|
||||
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
|
||||
} else {
|
||||
// only a single char
|
||||
return str.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean spec field name (trim of "is" from boolean types)
|
||||
*/
|
||||
private String getFieldName(Field field, Class<?> beanType) {
|
||||
|
||||
String name = field.getName();
|
||||
|
||||
if ((Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType())) && name.startsWith("is")
|
||||
&& name.length() > 2) {
|
||||
|
||||
// it is a boolean type field starting with "is"
|
||||
char c = name.charAt(2);
|
||||
if (Character.isUpperCase(c)) {
|
||||
String msg = "trimming off 'is' from boolean field name " + name + " in class " + beanType.getName();
|
||||
logger.info(msg);
|
||||
|
||||
return name.substring(2);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static getter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findGetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject) {
|
||||
|
||||
String methGetName = "get" + initFieldName;
|
||||
String methIsName = "is" + initFieldName;
|
||||
String scalaGet = field.getName();
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
if ((scalaObject && m.getName().equals(scalaGet)) || m.getName().equals(methGetName)
|
||||
|| m.getName().equals(methIsName)) {
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 0) {
|
||||
if (field.getType().equals(m.getReturnType())) {
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
// we find it...
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static setter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findSetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject) {
|
||||
|
||||
String methSetName = "set" + initFieldName;
|
||||
String scalaSetName = field.getName() + "_$eq";
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
|
||||
if ((scalaObject && m.getName().equals(scalaSetName)) || m.getName().equals(methSetName)) {
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 1 && field.getType().equals(params[0])) {
|
||||
if (void.class.equals(m.getReturnType())) {
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?> targetType, ManyType manyType) {
|
||||
|
||||
try {
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(targetType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, manyType);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("expected non-scalar type" + e.getMessage());
|
||||
}
|
||||
// TODO: Handle Collection of CompoundType and Embedded Type
|
||||
return new DeployBeanPropertyAssocMany(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
|
||||
|
||||
Class<?> propertyType = field.getType();
|
||||
|
||||
ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
|
||||
|
||||
if (manyToOne != null){
|
||||
Class<?> tt = manyToOne.targetEntity();
|
||||
|
||||
if (tt != null && !tt.equals(void.class)){
|
||||
propertyType = tt;
|
||||
logger.debug("target type" + tt);
|
||||
}
|
||||
}
|
||||
Class<?> innerType = propertyType;
|
||||
|
||||
String specialTypeKey = getSpecialScalarType(field);
|
||||
if (specialTypeKey != null) {
|
||||
ScalarType<?> scalarType = typeManager.getScalarTypeFromKey(specialTypeKey);
|
||||
if (scalarType == null) {
|
||||
logger.error("Could not find ScalarType to match key ["+specialTypeKey+"]");
|
||||
} else {
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
}
|
||||
|
||||
// check for Collection type (list, set or map)
|
||||
ManyType manyType = determineManyType.getManyType(propertyType);
|
||||
|
||||
if (manyType != null) {
|
||||
// List, Set or Map based object
|
||||
Class<?> targetType = determineTargetType(field);
|
||||
if (targetType == null) {
|
||||
Transient transAnnotation = field.getAnnotation(Transient.class);
|
||||
if (transAnnotation != null) {
|
||||
// not supporting this field (generic type used)
|
||||
return null;
|
||||
}
|
||||
logger.warn("Could not find parameter type (via reflection) on " + desc.getFullName() + " " + field.getName());
|
||||
}
|
||||
return createManyType(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
if (innerType.isEnum() || innerType.isPrimitive()) {
|
||||
return new DeployBeanProperty(desc, propertyType, null, null);
|
||||
}
|
||||
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(innerType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
|
||||
CtCompoundType<?> compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
if (isTransientField(field)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(innerType);
|
||||
if (checkImmutable.isImmutable()) {
|
||||
if (checkImmutable.isCompoundType()) {
|
||||
// use reflection to support compound immutable value objects
|
||||
typeManager.recursiveCreateScalarDataReader(innerType);
|
||||
compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
} else {
|
||||
// use reflection to support simple immutable value objects
|
||||
scalarType = typeManager.recursiveCreateScalarTypes(innerType);
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
}
|
||||
|
||||
return new DeployBeanPropertyAssocOne(desc, propertyType);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error with " + desc + " field:" + field.getName(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getSpecialScalarType(Field field) {
|
||||
|
||||
if (field.getAnnotation(ColumnHstore.class) != null) {
|
||||
return ScalarTypePostgresHstore.KEY;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isTransientField(Field field) {
|
||||
|
||||
Transient t = field.getAnnotation(Transient.class);
|
||||
return (t != null);
|
||||
}
|
||||
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType,
|
||||
Method getter, Method setter) {
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field);
|
||||
if (prop == null) {
|
||||
// transient annotation on unsupported type
|
||||
return null;
|
||||
} else {
|
||||
prop.setOwningType(beanType);
|
||||
prop.setName(field.getName());
|
||||
|
||||
// the getter or setter could be null if we are using
|
||||
// javaagent type enhancement. If we are using subclass
|
||||
// generation then we do need to find the getter and setter
|
||||
prop.setReadMethod(getter);
|
||||
prop.setWriteMethod(setter);
|
||||
prop.setField(field);
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the type of the List,Set or Map. Not been set explicitly so determine this from
|
||||
* ParameterizedType.
|
||||
*/
|
||||
private Class<?> determineTargetType(Field field) {
|
||||
|
||||
Type genType = field.getGenericType();
|
||||
if (genType instanceof ParameterizedType) {
|
||||
ParameterizedType ptype = (ParameterizedType) genType;
|
||||
|
||||
Type[] typeArgs = ptype.getActualTypeArguments();
|
||||
if (typeArgs.length == 1) {
|
||||
// probably a Set or List
|
||||
if (typeArgs[0] instanceof Class<?>) {
|
||||
return (Class<?>) typeArgs[0];
|
||||
}
|
||||
// throw new RuntimeException("Unexpected Parameterised Type? "+typeArgs[0]);
|
||||
return null;
|
||||
}
|
||||
if (typeArgs.length == 2) {
|
||||
// this is probably a Map
|
||||
if (typeArgs[1] instanceof ParameterizedType) {
|
||||
// not supporting ParameterizedType on Map.
|
||||
return null;
|
||||
}
|
||||
return (Class<?>) typeArgs[1];
|
||||
}
|
||||
}
|
||||
// if targetType is null, then must be set in annotations
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,165 +1,165 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.sql.Types;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Inheritance;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
|
||||
/**
|
||||
* Builds the InheritInfo deployment information.
|
||||
*/
|
||||
public class DeployInherit {
|
||||
|
||||
private final Map<Class<?>, DeployInheritInfo> deployMap = new LinkedHashMap<Class<?>, DeployInheritInfo>();
|
||||
|
||||
private final Map<Class<?>, InheritInfo> finalMap = new LinkedHashMap<Class<?>, InheritInfo>();
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
/**
|
||||
* Create the InheritInfoDeploy.
|
||||
*/
|
||||
public DeployInherit(BootupClasses bootupClasses) {
|
||||
this.bootupClasses = bootupClasses;
|
||||
initialise();
|
||||
}
|
||||
|
||||
public void process(DeployBeanDescriptor<?> desc) {
|
||||
InheritInfo inheritInfo = finalMap.get(desc.getBeanType());
|
||||
desc.setInheritInfo(inheritInfo);
|
||||
}
|
||||
|
||||
private void initialise() {
|
||||
List<Class<?>> entityList = bootupClasses.getEntities();
|
||||
|
||||
findInheritClasses(entityList);
|
||||
buildDeployTree();
|
||||
buildFinalTree();
|
||||
}
|
||||
|
||||
private void findInheritClasses(List<Class<?>> entityList) {
|
||||
|
||||
// go through each class and initialise the info object...
|
||||
for (Class<?> cls : entityList) {
|
||||
if (isInheritanceClass(cls)) {
|
||||
DeployInheritInfo info = createInfo(cls);
|
||||
deployMap.put(cls, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildDeployTree() {
|
||||
|
||||
for (DeployInheritInfo info : deployMap.values()) {
|
||||
if (!info.isRoot()) {
|
||||
DeployInheritInfo parent = getInfo(info.getParent());
|
||||
parent.addChild(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFinalTree() {
|
||||
|
||||
for (DeployInheritInfo deploy : deployMap.values()) {
|
||||
if (deploy.isRoot()) {
|
||||
// build tree top down...
|
||||
createFinalInfo(null, null, deploy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InheritInfo createFinalInfo(InheritInfo root, InheritInfo parent, DeployInheritInfo deploy) {
|
||||
|
||||
InheritInfo node = new InheritInfo(root, parent, deploy);
|
||||
if (parent != null) {
|
||||
parent.addChild(node);
|
||||
}
|
||||
finalMap.put(node.getType(), node);
|
||||
|
||||
if (root == null) {
|
||||
root = node;
|
||||
}
|
||||
|
||||
// buildFinalChildren(root, child, deploy);
|
||||
for (DeployInheritInfo childDeploy : deploy.children()) {
|
||||
createFinalInfo(root, node, childDeploy);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the InheritInfo for a given class.
|
||||
*/
|
||||
private DeployInheritInfo getInfo(Class<?> cls) {
|
||||
return deployMap.get(cls);
|
||||
}
|
||||
|
||||
private DeployInheritInfo createInfo(Class<?> cls) {
|
||||
|
||||
DeployInheritInfo info = new DeployInheritInfo(cls);
|
||||
|
||||
Class<?> parent = findParent(cls);
|
||||
if (parent != null) {
|
||||
info.setParent(parent);
|
||||
} else {
|
||||
// its the root of inheritance tree...
|
||||
}
|
||||
|
||||
Inheritance ia = (Inheritance) cls.getAnnotation(Inheritance.class);
|
||||
if (ia != null) {
|
||||
ia.strategy();
|
||||
}
|
||||
DiscriminatorColumn da = (DiscriminatorColumn) cls.getAnnotation(DiscriminatorColumn.class);
|
||||
if (da != null) {
|
||||
// lowercase the discriminator column for RawSql and JSON
|
||||
info.setDiscriminatorColumn(da.name().toLowerCase());
|
||||
DiscriminatorType discriminatorType = da.discriminatorType();
|
||||
if (discriminatorType.equals(DiscriminatorType.INTEGER)){
|
||||
info.setDiscriminatorType(Types.INTEGER);
|
||||
} else {
|
||||
info.setDiscriminatorType(Types.VARCHAR);
|
||||
}
|
||||
info.setDiscriminatorLength(da.length());
|
||||
}
|
||||
|
||||
DiscriminatorValue dv = (DiscriminatorValue) cls.getAnnotation(DiscriminatorValue.class);
|
||||
if (dv != null) {
|
||||
info.setDiscriminatorValue(dv.value());
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private Class<?> findParent(Class<?> cls) {
|
||||
Class<?> superCls = cls.getSuperclass();
|
||||
if (isInheritanceClass(superCls)) {
|
||||
return superCls;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInheritanceClass(Class<?> cls) {
|
||||
if (cls.equals(Object.class)) {
|
||||
return false;
|
||||
}
|
||||
Annotation a = cls.getAnnotation(Inheritance.class);
|
||||
if (a != null) {
|
||||
return true;
|
||||
}
|
||||
// search up the inheritance heirarchy
|
||||
return isInheritanceClass(cls.getSuperclass());
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.sql.Types;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Inheritance;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
|
||||
/**
|
||||
* Builds the InheritInfo deployment information.
|
||||
*/
|
||||
public class DeployInherit {
|
||||
|
||||
private final Map<Class<?>, DeployInheritInfo> deployMap = new LinkedHashMap<Class<?>, DeployInheritInfo>();
|
||||
|
||||
private final Map<Class<?>, InheritInfo> finalMap = new LinkedHashMap<Class<?>, InheritInfo>();
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
/**
|
||||
* Create the InheritInfoDeploy.
|
||||
*/
|
||||
public DeployInherit(BootupClasses bootupClasses) {
|
||||
this.bootupClasses = bootupClasses;
|
||||
initialise();
|
||||
}
|
||||
|
||||
public void process(DeployBeanDescriptor<?> desc) {
|
||||
InheritInfo inheritInfo = finalMap.get(desc.getBeanType());
|
||||
desc.setInheritInfo(inheritInfo);
|
||||
}
|
||||
|
||||
private void initialise() {
|
||||
List<Class<?>> entityList = bootupClasses.getEntities();
|
||||
|
||||
findInheritClasses(entityList);
|
||||
buildDeployTree();
|
||||
buildFinalTree();
|
||||
}
|
||||
|
||||
private void findInheritClasses(List<Class<?>> entityList) {
|
||||
|
||||
// go through each class and initialise the info object...
|
||||
for (Class<?> cls : entityList) {
|
||||
if (isInheritanceClass(cls)) {
|
||||
DeployInheritInfo info = createInfo(cls);
|
||||
deployMap.put(cls, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildDeployTree() {
|
||||
|
||||
for (DeployInheritInfo info : deployMap.values()) {
|
||||
if (!info.isRoot()) {
|
||||
DeployInheritInfo parent = getInfo(info.getParent());
|
||||
parent.addChild(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFinalTree() {
|
||||
|
||||
for (DeployInheritInfo deploy : deployMap.values()) {
|
||||
if (deploy.isRoot()) {
|
||||
// build tree top down...
|
||||
createFinalInfo(null, null, deploy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InheritInfo createFinalInfo(InheritInfo root, InheritInfo parent, DeployInheritInfo deploy) {
|
||||
|
||||
InheritInfo node = new InheritInfo(root, parent, deploy);
|
||||
if (parent != null) {
|
||||
parent.addChild(node);
|
||||
}
|
||||
finalMap.put(node.getType(), node);
|
||||
|
||||
if (root == null) {
|
||||
root = node;
|
||||
}
|
||||
|
||||
// buildFinalChildren(root, child, deploy);
|
||||
for (DeployInheritInfo childDeploy : deploy.children()) {
|
||||
createFinalInfo(root, node, childDeploy);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the InheritInfo for a given class.
|
||||
*/
|
||||
private DeployInheritInfo getInfo(Class<?> cls) {
|
||||
return deployMap.get(cls);
|
||||
}
|
||||
|
||||
private DeployInheritInfo createInfo(Class<?> cls) {
|
||||
|
||||
DeployInheritInfo info = new DeployInheritInfo(cls);
|
||||
|
||||
Class<?> parent = findParent(cls);
|
||||
if (parent != null) {
|
||||
info.setParent(parent);
|
||||
} else {
|
||||
// its the root of inheritance tree...
|
||||
}
|
||||
|
||||
Inheritance ia = (Inheritance) cls.getAnnotation(Inheritance.class);
|
||||
if (ia != null) {
|
||||
ia.strategy();
|
||||
}
|
||||
DiscriminatorColumn da = (DiscriminatorColumn) cls.getAnnotation(DiscriminatorColumn.class);
|
||||
if (da != null) {
|
||||
// lowercase the discriminator column for RawSql and JSON
|
||||
info.setDiscriminatorColumn(da.name().toLowerCase());
|
||||
DiscriminatorType discriminatorType = da.discriminatorType();
|
||||
if (discriminatorType.equals(DiscriminatorType.INTEGER)){
|
||||
info.setDiscriminatorType(Types.INTEGER);
|
||||
} else {
|
||||
info.setDiscriminatorType(Types.VARCHAR);
|
||||
}
|
||||
info.setDiscriminatorLength(da.length());
|
||||
}
|
||||
|
||||
DiscriminatorValue dv = (DiscriminatorValue) cls.getAnnotation(DiscriminatorValue.class);
|
||||
if (dv != null) {
|
||||
info.setDiscriminatorValue(dv.value());
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private Class<?> findParent(Class<?> cls) {
|
||||
Class<?> superCls = cls.getSuperclass();
|
||||
if (isInheritanceClass(superCls)) {
|
||||
return superCls;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInheritanceClass(Class<?> cls) {
|
||||
if (cls.equals(Object.class)) {
|
||||
return false;
|
||||
}
|
||||
Annotation a = cls.getAnnotation(Inheritance.class);
|
||||
if (a != null) {
|
||||
return true;
|
||||
}
|
||||
// search up the inheritance heirarchy
|
||||
return isInheritanceClass(cls.getSuperclass());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+263
-263
@@ -1,263 +1,263 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
|
||||
/**
|
||||
* Represents a node in the Inheritance tree.
|
||||
* Holds information regarding Super Subclass support.
|
||||
*/
|
||||
public class DeployInheritInfo {
|
||||
|
||||
/**
|
||||
* the default discriminator column according to the JPA 1.0 spec.
|
||||
*/
|
||||
private static final String JPA_DEFAULT_DISCRIM_COLUMN = "dtype";
|
||||
|
||||
private int discriminatorLength;
|
||||
|
||||
private int discriminatorType;
|
||||
|
||||
private String discriminatorStringValue;
|
||||
private Object discriminatorObjectValue;
|
||||
|
||||
private String discriminatorColumn;
|
||||
|
||||
private String discriminatorWhere;
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
private Class<?> parent;
|
||||
|
||||
private ArrayList<DeployInheritInfo> children = new ArrayList<DeployInheritInfo>();
|
||||
|
||||
/**
|
||||
* Create for a given type.
|
||||
*/
|
||||
public DeployInheritInfo(Class<?> type){
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the type.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the root object.
|
||||
*/
|
||||
public Class<?> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of the root object.
|
||||
*/
|
||||
public void setParent(Class<?> parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is abstract node.
|
||||
*/
|
||||
public boolean isAbstract() {
|
||||
return (discriminatorObjectValue == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the root node.
|
||||
*/
|
||||
public boolean isRoot(){
|
||||
return parent == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the child nodes.
|
||||
*/
|
||||
public List<DeployInheritInfo> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child node.
|
||||
*/
|
||||
public void addChild(DeployInheritInfo childInfo){
|
||||
children.add(childInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the derived where for the discriminator.
|
||||
*/
|
||||
public String getDiscriminatorWhere() {
|
||||
return discriminatorWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the derived where for the discriminator.
|
||||
*/
|
||||
public void setDiscriminatorWhere(String discriminatorWhere) {
|
||||
this.discriminatorWhere = discriminatorWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column name of the discriminator.
|
||||
*/
|
||||
public String getDiscriminatorColumn(InheritInfo parent) {
|
||||
if (discriminatorColumn == null){
|
||||
if (parent == null){
|
||||
discriminatorColumn = JPA_DEFAULT_DISCRIM_COLUMN;
|
||||
} else {
|
||||
discriminatorColumn = parent.getDiscriminatorColumn();
|
||||
}
|
||||
}
|
||||
return discriminatorColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column name of the discriminator.
|
||||
*/
|
||||
public void setDiscriminatorColumn(String discriminatorColumn) {
|
||||
this.discriminatorColumn = discriminatorColumn;
|
||||
}
|
||||
|
||||
public int getDiscriminatorLength(InheritInfo parent) {
|
||||
if (discriminatorLength == 0){
|
||||
if (parent == null){
|
||||
discriminatorLength = 10;
|
||||
} else {
|
||||
discriminatorLength = parent.getDiscriminatorLength();
|
||||
}
|
||||
}
|
||||
return discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sql type of the discriminator value.
|
||||
*/
|
||||
public int getDiscriminatorType(InheritInfo parent) {
|
||||
if (discriminatorType == 0){
|
||||
if (parent == null){
|
||||
discriminatorType = Types.VARCHAR;
|
||||
} else {
|
||||
discriminatorType = parent.getDiscriminatorType();
|
||||
}
|
||||
}
|
||||
return discriminatorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sql type of the discriminator.
|
||||
*/
|
||||
public void setDiscriminatorType(int discriminatorType) {
|
||||
this.discriminatorType = discriminatorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the discriminator column.
|
||||
*/
|
||||
public int getDiscriminatorLength() {
|
||||
return discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of the discriminator column.
|
||||
*/
|
||||
public void setDiscriminatorLength(int discriminatorLength) {
|
||||
this.discriminatorLength = discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the discriminator value for this node.
|
||||
*/
|
||||
public Object getDiscriminatorObjectValue() {
|
||||
return discriminatorObjectValue;
|
||||
}
|
||||
|
||||
public String getDiscriminatorStringValue() {
|
||||
return discriminatorStringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the discriminator value for this node.
|
||||
*/
|
||||
public void setDiscriminatorValue(String value) {
|
||||
if (value != null){
|
||||
value = value.trim();
|
||||
if (value.length() == 0){
|
||||
value = null;
|
||||
} else {
|
||||
discriminatorStringValue = value;
|
||||
// convert the value if desired
|
||||
if (discriminatorType == Types.INTEGER){
|
||||
this.discriminatorObjectValue = Integer.valueOf(value.toString());
|
||||
} else {
|
||||
this.discriminatorObjectValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getWhere() {
|
||||
|
||||
List<Object> discList = new ArrayList<Object>();
|
||||
|
||||
appendDiscriminator(discList);
|
||||
|
||||
return buildWhereLiteral(discList);
|
||||
}
|
||||
|
||||
private void appendDiscriminator(List<Object> list) {
|
||||
if (discriminatorObjectValue != null){
|
||||
list.add(discriminatorObjectValue);
|
||||
}
|
||||
for (DeployInheritInfo child : children) {
|
||||
child.appendDiscriminator(list);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildWhereLiteral(List<Object> discList) {
|
||||
int size = discList.size();
|
||||
if (size == 0){
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(discriminatorColumn);
|
||||
if (size == 1){
|
||||
sb.append(" = ");
|
||||
} else {
|
||||
sb.append(" in (");
|
||||
}
|
||||
for (int i = 0; i < discList.size(); i++) {
|
||||
appendSqlLiteralValue(i, discList.get(i), sb);
|
||||
}
|
||||
if (size > 1){
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendSqlLiteralValue(int count, Object value, StringBuilder sb) {
|
||||
if (count > 0){
|
||||
sb.append(",");
|
||||
}
|
||||
if (value instanceof String){
|
||||
sb.append("'").append(value).append("'");
|
||||
} else {
|
||||
sb.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("InheritInfo[").append(type.getName()).append("]");
|
||||
sb.append(" root[").append(parent.getName()).append("]");
|
||||
sb.append(" disValue[").append(discriminatorStringValue).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
|
||||
/**
|
||||
* Represents a node in the Inheritance tree.
|
||||
* Holds information regarding Super Subclass support.
|
||||
*/
|
||||
public class DeployInheritInfo {
|
||||
|
||||
/**
|
||||
* the default discriminator column according to the JPA 1.0 spec.
|
||||
*/
|
||||
private static final String JPA_DEFAULT_DISCRIM_COLUMN = "dtype";
|
||||
|
||||
private int discriminatorLength;
|
||||
|
||||
private int discriminatorType;
|
||||
|
||||
private String discriminatorStringValue;
|
||||
private Object discriminatorObjectValue;
|
||||
|
||||
private String discriminatorColumn;
|
||||
|
||||
private String discriminatorWhere;
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
private Class<?> parent;
|
||||
|
||||
private ArrayList<DeployInheritInfo> children = new ArrayList<DeployInheritInfo>();
|
||||
|
||||
/**
|
||||
* Create for a given type.
|
||||
*/
|
||||
public DeployInheritInfo(Class<?> type){
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the type.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the root object.
|
||||
*/
|
||||
public Class<?> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of the root object.
|
||||
*/
|
||||
public void setParent(Class<?> parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is abstract node.
|
||||
*/
|
||||
public boolean isAbstract() {
|
||||
return (discriminatorObjectValue == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the root node.
|
||||
*/
|
||||
public boolean isRoot(){
|
||||
return parent == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the child nodes.
|
||||
*/
|
||||
public List<DeployInheritInfo> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child node.
|
||||
*/
|
||||
public void addChild(DeployInheritInfo childInfo){
|
||||
children.add(childInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the derived where for the discriminator.
|
||||
*/
|
||||
public String getDiscriminatorWhere() {
|
||||
return discriminatorWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the derived where for the discriminator.
|
||||
*/
|
||||
public void setDiscriminatorWhere(String discriminatorWhere) {
|
||||
this.discriminatorWhere = discriminatorWhere;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column name of the discriminator.
|
||||
*/
|
||||
public String getDiscriminatorColumn(InheritInfo parent) {
|
||||
if (discriminatorColumn == null){
|
||||
if (parent == null){
|
||||
discriminatorColumn = JPA_DEFAULT_DISCRIM_COLUMN;
|
||||
} else {
|
||||
discriminatorColumn = parent.getDiscriminatorColumn();
|
||||
}
|
||||
}
|
||||
return discriminatorColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column name of the discriminator.
|
||||
*/
|
||||
public void setDiscriminatorColumn(String discriminatorColumn) {
|
||||
this.discriminatorColumn = discriminatorColumn;
|
||||
}
|
||||
|
||||
public int getDiscriminatorLength(InheritInfo parent) {
|
||||
if (discriminatorLength == 0){
|
||||
if (parent == null){
|
||||
discriminatorLength = 10;
|
||||
} else {
|
||||
discriminatorLength = parent.getDiscriminatorLength();
|
||||
}
|
||||
}
|
||||
return discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sql type of the discriminator value.
|
||||
*/
|
||||
public int getDiscriminatorType(InheritInfo parent) {
|
||||
if (discriminatorType == 0){
|
||||
if (parent == null){
|
||||
discriminatorType = Types.VARCHAR;
|
||||
} else {
|
||||
discriminatorType = parent.getDiscriminatorType();
|
||||
}
|
||||
}
|
||||
return discriminatorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sql type of the discriminator.
|
||||
*/
|
||||
public void setDiscriminatorType(int discriminatorType) {
|
||||
this.discriminatorType = discriminatorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the discriminator column.
|
||||
*/
|
||||
public int getDiscriminatorLength() {
|
||||
return discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of the discriminator column.
|
||||
*/
|
||||
public void setDiscriminatorLength(int discriminatorLength) {
|
||||
this.discriminatorLength = discriminatorLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the discriminator value for this node.
|
||||
*/
|
||||
public Object getDiscriminatorObjectValue() {
|
||||
return discriminatorObjectValue;
|
||||
}
|
||||
|
||||
public String getDiscriminatorStringValue() {
|
||||
return discriminatorStringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the discriminator value for this node.
|
||||
*/
|
||||
public void setDiscriminatorValue(String value) {
|
||||
if (value != null){
|
||||
value = value.trim();
|
||||
if (value.length() == 0){
|
||||
value = null;
|
||||
} else {
|
||||
discriminatorStringValue = value;
|
||||
// convert the value if desired
|
||||
if (discriminatorType == Types.INTEGER){
|
||||
this.discriminatorObjectValue = Integer.valueOf(value.toString());
|
||||
} else {
|
||||
this.discriminatorObjectValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getWhere() {
|
||||
|
||||
List<Object> discList = new ArrayList<Object>();
|
||||
|
||||
appendDiscriminator(discList);
|
||||
|
||||
return buildWhereLiteral(discList);
|
||||
}
|
||||
|
||||
private void appendDiscriminator(List<Object> list) {
|
||||
if (discriminatorObjectValue != null){
|
||||
list.add(discriminatorObjectValue);
|
||||
}
|
||||
for (DeployInheritInfo child : children) {
|
||||
child.appendDiscriminator(list);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildWhereLiteral(List<Object> discList) {
|
||||
int size = discList.size();
|
||||
if (size == 0){
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(discriminatorColumn);
|
||||
if (size == 1){
|
||||
sb.append(" = ");
|
||||
} else {
|
||||
sb.append(" in (");
|
||||
}
|
||||
for (int i = 0; i < discList.size(); i++) {
|
||||
appendSqlLiteralValue(i, discList.get(i), sb);
|
||||
}
|
||||
if (size > 1){
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendSqlLiteralValue(int count, Object value, StringBuilder sb) {
|
||||
if (count > 0){
|
||||
sb.append(",");
|
||||
}
|
||||
if (value instanceof String){
|
||||
sb.append("'").append(value).append("'");
|
||||
} else {
|
||||
sb.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("InheritInfo[").append(type.getName()).append("]");
|
||||
sb.append(" root[").append(parent.getName()).append("]");
|
||||
sb.append(" disValue[").append(discriminatorStringValue).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,228 +1,228 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.sql.Types;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.EncryptDeploy;
|
||||
import com.avaje.ebean.config.EncryptDeployManager;
|
||||
import com.avaje.ebean.config.EncryptKeyManager;
|
||||
import com.avaje.ebean.config.Encryptor;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeEnumStandard;
|
||||
import com.avaje.ebeaninternal.server.type.SimpleAesEncryptor;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Utility object to help processing deployment information.
|
||||
*/
|
||||
public class DeployUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployUtil.class);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Assumes CLOB rather than LONGVARCHAR.
|
||||
*/
|
||||
private static final int dbCLOBType = Types.CLOB;
|
||||
|
||||
/**
|
||||
* Assumes BLOB rather than LONGVARBINARY. This should probably be
|
||||
* configurable.
|
||||
*/
|
||||
private static final int dbBLOBType = Types.BLOB;
|
||||
|
||||
private final NamingConvention namingConvention;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final String manyToManyAlias;
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
private final EncryptDeployManager encryptDeployManager;
|
||||
|
||||
private final EncryptKeyManager encryptKeyManager;
|
||||
|
||||
private final Encryptor bytesEncryptor;
|
||||
|
||||
public DeployUtil(TypeManager typeMgr, ServerConfig serverConfig) {
|
||||
|
||||
this.typeManager = typeMgr;
|
||||
this.namingConvention = serverConfig.getNamingConvention();
|
||||
this.dbPlatform = serverConfig.getDatabasePlatform();
|
||||
this.encryptDeployManager = serverConfig.getEncryptDeployManager();
|
||||
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
|
||||
|
||||
Encryptor be = serverConfig.getEncryptor();
|
||||
this.bytesEncryptor = be != null ? be : new SimpleAesEncryptor();
|
||||
|
||||
// this alias is used for ManyToMany lazy loading queries
|
||||
this.manyToManyAlias = "zzzzzz";
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
public DatabasePlatform getDbPlatform() {
|
||||
return dbPlatform;
|
||||
}
|
||||
|
||||
public NamingConvention getNamingConvention() {
|
||||
return namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the EncryptKeyManager has been defined.
|
||||
*/
|
||||
public void checkEncryptKeyManagerDefined(String fullPropName) {
|
||||
if (encryptKeyManager == null){
|
||||
String msg = "Using encryption on "+fullPropName+" but no EncryptKeyManager defined!";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public EncryptDeploy getEncryptDeploy(TableName table, String column) {
|
||||
if (encryptDeployManager == null){
|
||||
return EncryptDeploy.ANNOTATION;
|
||||
}
|
||||
return encryptDeployManager.getEncryptDeploy(table, column);
|
||||
}
|
||||
|
||||
public DataEncryptSupport createDataEncryptSupport(String table, String column) {
|
||||
return new DataEncryptSupport(encryptKeyManager, bytesEncryptor, table, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table alias used for ManyToMany joins.
|
||||
*/
|
||||
public String getManyToManyAlias() {
|
||||
return manyToManyAlias;
|
||||
}
|
||||
|
||||
public ScalarType<?> setEnumScalarType(Enumerated enumerated, DeployBeanProperty prop) {
|
||||
|
||||
Class<?> enumType = prop.getPropertyType();
|
||||
if (!enumType.isEnum()) {
|
||||
throw new IllegalArgumentException("Class ["+enumType+"] is Not a Enum?");
|
||||
}
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(enumType);
|
||||
if (scalarType == null) {
|
||||
// see if it has a Mapping in avaje.properties
|
||||
scalarType = typeManager.createEnumScalarType(enumType);
|
||||
if (scalarType == null){
|
||||
// use JPA normal Enum type (without mapping)
|
||||
EnumType type = enumerated != null? enumerated.value(): null;
|
||||
scalarType = createEnumScalarTypePerSpec(enumType, type, prop.getDbType());
|
||||
}
|
||||
|
||||
typeManager.add(scalarType);
|
||||
}
|
||||
prop.setScalarType(scalarType);
|
||||
prop.setDbType(scalarType.getJdbcType());
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
private ScalarType<?> createEnumScalarTypePerSpec(Class<?> enumType, EnumType type, int dbType) {
|
||||
|
||||
if (type == null) {
|
||||
// default as per spec is ORDINAL
|
||||
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
|
||||
|
||||
} else if (type == EnumType.ORDINAL) {
|
||||
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
|
||||
|
||||
} else {
|
||||
return new ScalarTypeEnumStandard.StringEnum(enumType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ScalarType for this property.
|
||||
* <p>
|
||||
* This determines if there is a conversion required from the logical (bean)
|
||||
* type to a DB (jdbc) type. This is the case for java.util.Date etc.
|
||||
* </p>
|
||||
*/
|
||||
public void setScalarType(DeployBeanProperty property) {
|
||||
|
||||
if (property.getScalarType() != null){
|
||||
// already has a ScalarType assigned.
|
||||
// this will be an Enum type...
|
||||
return;
|
||||
}
|
||||
if (property instanceof DeployBeanPropertyCompound){
|
||||
// compound properties have a CvoInternalType instead
|
||||
return;
|
||||
}
|
||||
|
||||
ScalarType<?> scalarType = getScalarType(property);
|
||||
if (scalarType != null){
|
||||
// set the jdbc type this maps to
|
||||
|
||||
property.setDbType(scalarType.getJdbcType());
|
||||
property.setScalarType(scalarType);
|
||||
}
|
||||
}
|
||||
|
||||
private ScalarType<?> getScalarType(DeployBeanProperty property) {
|
||||
|
||||
// Note that Temporal types already have dbType
|
||||
// set via annotations
|
||||
Class<?> propType = property.getPropertyType();
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(propType, property.getDbType());
|
||||
if (scalarType != null) {
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
String msg = property.getFullBeanName()+" has no ScalarType - type[" + propType.getName() + "]";
|
||||
if (!property.isTransient()){
|
||||
throw new PersistenceException(msg);
|
||||
|
||||
} else {
|
||||
// this is ok...
|
||||
logger.trace("... transient property "+msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This property is marked as a Lob object.
|
||||
*/
|
||||
public void setLobType(DeployBeanProperty prop) {
|
||||
|
||||
// is String or byte[] ? used to determine if its a CLOB or BLOB
|
||||
Class<?> type = prop.getPropertyType();
|
||||
|
||||
// this also sets the lob flag on DeployBeanProperty
|
||||
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
|
||||
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(type, lobType);
|
||||
if (scalarType == null) {
|
||||
// this should never occur actually
|
||||
throw new RuntimeException("No ScalarType for LOB type ["+type+"] ["+lobType+"]");
|
||||
}
|
||||
prop.setDbType(lobType);
|
||||
prop.setScalarType(scalarType);
|
||||
}
|
||||
|
||||
public boolean isClobType(Class<?> type){
|
||||
if (type.equals(String.class)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.sql.Types;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.EncryptDeploy;
|
||||
import com.avaje.ebean.config.EncryptDeployManager;
|
||||
import com.avaje.ebean.config.EncryptKeyManager;
|
||||
import com.avaje.ebean.config.Encryptor;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeEnumStandard;
|
||||
import com.avaje.ebeaninternal.server.type.SimpleAesEncryptor;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Utility object to help processing deployment information.
|
||||
*/
|
||||
public class DeployUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployUtil.class);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Assumes CLOB rather than LONGVARCHAR.
|
||||
*/
|
||||
private static final int dbCLOBType = Types.CLOB;
|
||||
|
||||
/**
|
||||
* Assumes BLOB rather than LONGVARBINARY. This should probably be
|
||||
* configurable.
|
||||
*/
|
||||
private static final int dbBLOBType = Types.BLOB;
|
||||
|
||||
private final NamingConvention namingConvention;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final String manyToManyAlias;
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
private final EncryptDeployManager encryptDeployManager;
|
||||
|
||||
private final EncryptKeyManager encryptKeyManager;
|
||||
|
||||
private final Encryptor bytesEncryptor;
|
||||
|
||||
public DeployUtil(TypeManager typeMgr, ServerConfig serverConfig) {
|
||||
|
||||
this.typeManager = typeMgr;
|
||||
this.namingConvention = serverConfig.getNamingConvention();
|
||||
this.dbPlatform = serverConfig.getDatabasePlatform();
|
||||
this.encryptDeployManager = serverConfig.getEncryptDeployManager();
|
||||
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
|
||||
|
||||
Encryptor be = serverConfig.getEncryptor();
|
||||
this.bytesEncryptor = be != null ? be : new SimpleAesEncryptor();
|
||||
|
||||
// this alias is used for ManyToMany lazy loading queries
|
||||
this.manyToManyAlias = "zzzzzz";
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
public DatabasePlatform getDbPlatform() {
|
||||
return dbPlatform;
|
||||
}
|
||||
|
||||
public NamingConvention getNamingConvention() {
|
||||
return namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the EncryptKeyManager has been defined.
|
||||
*/
|
||||
public void checkEncryptKeyManagerDefined(String fullPropName) {
|
||||
if (encryptKeyManager == null){
|
||||
String msg = "Using encryption on "+fullPropName+" but no EncryptKeyManager defined!";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public EncryptDeploy getEncryptDeploy(TableName table, String column) {
|
||||
if (encryptDeployManager == null){
|
||||
return EncryptDeploy.ANNOTATION;
|
||||
}
|
||||
return encryptDeployManager.getEncryptDeploy(table, column);
|
||||
}
|
||||
|
||||
public DataEncryptSupport createDataEncryptSupport(String table, String column) {
|
||||
return new DataEncryptSupport(encryptKeyManager, bytesEncryptor, table, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table alias used for ManyToMany joins.
|
||||
*/
|
||||
public String getManyToManyAlias() {
|
||||
return manyToManyAlias;
|
||||
}
|
||||
|
||||
public ScalarType<?> setEnumScalarType(Enumerated enumerated, DeployBeanProperty prop) {
|
||||
|
||||
Class<?> enumType = prop.getPropertyType();
|
||||
if (!enumType.isEnum()) {
|
||||
throw new IllegalArgumentException("Class ["+enumType+"] is Not a Enum?");
|
||||
}
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(enumType);
|
||||
if (scalarType == null) {
|
||||
// see if it has a Mapping in avaje.properties
|
||||
scalarType = typeManager.createEnumScalarType(enumType);
|
||||
if (scalarType == null){
|
||||
// use JPA normal Enum type (without mapping)
|
||||
EnumType type = enumerated != null? enumerated.value(): null;
|
||||
scalarType = createEnumScalarTypePerSpec(enumType, type, prop.getDbType());
|
||||
}
|
||||
|
||||
typeManager.add(scalarType);
|
||||
}
|
||||
prop.setScalarType(scalarType);
|
||||
prop.setDbType(scalarType.getJdbcType());
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
private ScalarType<?> createEnumScalarTypePerSpec(Class<?> enumType, EnumType type, int dbType) {
|
||||
|
||||
if (type == null) {
|
||||
// default as per spec is ORDINAL
|
||||
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
|
||||
|
||||
} else if (type == EnumType.ORDINAL) {
|
||||
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
|
||||
|
||||
} else {
|
||||
return new ScalarTypeEnumStandard.StringEnum(enumType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ScalarType for this property.
|
||||
* <p>
|
||||
* This determines if there is a conversion required from the logical (bean)
|
||||
* type to a DB (jdbc) type. This is the case for java.util.Date etc.
|
||||
* </p>
|
||||
*/
|
||||
public void setScalarType(DeployBeanProperty property) {
|
||||
|
||||
if (property.getScalarType() != null){
|
||||
// already has a ScalarType assigned.
|
||||
// this will be an Enum type...
|
||||
return;
|
||||
}
|
||||
if (property instanceof DeployBeanPropertyCompound){
|
||||
// compound properties have a CvoInternalType instead
|
||||
return;
|
||||
}
|
||||
|
||||
ScalarType<?> scalarType = getScalarType(property);
|
||||
if (scalarType != null){
|
||||
// set the jdbc type this maps to
|
||||
|
||||
property.setDbType(scalarType.getJdbcType());
|
||||
property.setScalarType(scalarType);
|
||||
}
|
||||
}
|
||||
|
||||
private ScalarType<?> getScalarType(DeployBeanProperty property) {
|
||||
|
||||
// Note that Temporal types already have dbType
|
||||
// set via annotations
|
||||
Class<?> propType = property.getPropertyType();
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(propType, property.getDbType());
|
||||
if (scalarType != null) {
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
String msg = property.getFullBeanName()+" has no ScalarType - type[" + propType.getName() + "]";
|
||||
if (!property.isTransient()){
|
||||
throw new PersistenceException(msg);
|
||||
|
||||
} else {
|
||||
// this is ok...
|
||||
logger.trace("... transient property "+msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This property is marked as a Lob object.
|
||||
*/
|
||||
public void setLobType(DeployBeanProperty prop) {
|
||||
|
||||
// is String or byte[] ? used to determine if its a CLOB or BLOB
|
||||
Class<?> type = prop.getPropertyType();
|
||||
|
||||
// this also sets the lob flag on DeployBeanProperty
|
||||
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
|
||||
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(type, lobType);
|
||||
if (scalarType == null) {
|
||||
// this should never occur actually
|
||||
throw new RuntimeException("No ScalarType for LOB type ["+type+"] ["+lobType+"]");
|
||||
}
|
||||
prop.setDbType(lobType);
|
||||
prop.setScalarType(scalarType);
|
||||
}
|
||||
|
||||
public boolean isClobType(Class<?> type){
|
||||
if (type.equals(String.class)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
|
||||
|
||||
/**
|
||||
* Read the deployment annotations for the bean.
|
||||
*/
|
||||
public class ReadAnnotations {
|
||||
|
||||
/**
|
||||
* Read the initial non-relationship annotations included Id and EmbeddedId.
|
||||
* <p>
|
||||
* We then have enough to create BeanTables which are used in readAssociations
|
||||
* to resolve the relationships etc.
|
||||
* </p>
|
||||
*/
|
||||
public void readInitial(DeployBeanInfo<?> info, boolean eagerFetchLobs){
|
||||
|
||||
try {
|
||||
new AnnotationClass(info).parse();
|
||||
new AnnotationFields(info, eagerFetchLobs).parse();
|
||||
|
||||
} catch (RuntimeException e){
|
||||
String msg = "Error reading annotations for "+info;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read and process the associated relationship annotations.
|
||||
* <p>
|
||||
* These can only be processed after the BeanTables have been created
|
||||
* </p>
|
||||
* <p>
|
||||
* This uses the factory as a call back to get the BeanTable for a given
|
||||
* associated bean.
|
||||
* </p>
|
||||
*/
|
||||
public void readAssociations(DeployBeanInfo<?> info, BeanDescriptorManager factory){
|
||||
|
||||
try {
|
||||
|
||||
new AnnotationAssocOnes(info, factory).parse();
|
||||
new AnnotationAssocManys(info, factory).parse();
|
||||
|
||||
// read the Sql annotations last because they may be
|
||||
// dependent on field level annotations
|
||||
new AnnotationSql(info).parse();
|
||||
|
||||
} catch (RuntimeException e){
|
||||
String msg = "Error reading annotations for "+info;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
|
||||
|
||||
/**
|
||||
* Read the deployment annotations for the bean.
|
||||
*/
|
||||
public class ReadAnnotations {
|
||||
|
||||
/**
|
||||
* Read the initial non-relationship annotations included Id and EmbeddedId.
|
||||
* <p>
|
||||
* We then have enough to create BeanTables which are used in readAssociations
|
||||
* to resolve the relationships etc.
|
||||
* </p>
|
||||
*/
|
||||
public void readInitial(DeployBeanInfo<?> info, boolean eagerFetchLobs){
|
||||
|
||||
try {
|
||||
new AnnotationClass(info).parse();
|
||||
new AnnotationFields(info, eagerFetchLobs).parse();
|
||||
|
||||
} catch (RuntimeException e){
|
||||
String msg = "Error reading annotations for "+info;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read and process the associated relationship annotations.
|
||||
* <p>
|
||||
* These can only be processed after the BeanTables have been created
|
||||
* </p>
|
||||
* <p>
|
||||
* This uses the factory as a call back to get the BeanTable for a given
|
||||
* associated bean.
|
||||
* </p>
|
||||
*/
|
||||
public void readAssociations(DeployBeanInfo<?> info, BeanDescriptorManager factory){
|
||||
|
||||
try {
|
||||
|
||||
new AnnotationAssocOnes(info, factory).parse();
|
||||
new AnnotationAssocManys(info, factory).parse();
|
||||
|
||||
// read the Sql annotations last because they may be
|
||||
// dependent on field level annotations
|
||||
new AnnotationSql(info).parse();
|
||||
|
||||
} catch (RuntimeException e){
|
||||
String msg = "Error reading annotations for "+info;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+51
-51
@@ -1,51 +1,51 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Mark transient properties.
|
||||
*/
|
||||
public class TransientProperties {
|
||||
|
||||
public TransientProperties() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark any additional properties as transient.
|
||||
*/
|
||||
public void process(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
List<DeployBeanProperty> props = desc.propertiesBase();
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
DeployBeanProperty prop = props.get(i);
|
||||
if (!prop.isDbRead() && !prop.isDbInsertable() && !prop.isDbUpdateable()) {
|
||||
// non-transient...
|
||||
prop.setTransient(true);
|
||||
}
|
||||
}
|
||||
|
||||
List<DeployBeanPropertyAssocOne<?>> ones = desc.propertiesAssocOne();
|
||||
for (int i = 0; i < ones.size(); i++) {
|
||||
DeployBeanPropertyAssocOne<?> prop = ones.get(i);
|
||||
if (prop.getBeanTable() == null) {
|
||||
if (!prop.isEmbedded()) {
|
||||
prop.setTransient(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<DeployBeanPropertyAssocMany<?>> manys = desc.propertiesAssocMany();
|
||||
for (int i = 0; i < manys.size(); i++) {
|
||||
DeployBeanPropertyAssocMany<?> prop = manys.get(i);
|
||||
if (prop.getBeanTable() == null) {
|
||||
prop.setTransient(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Mark transient properties.
|
||||
*/
|
||||
public class TransientProperties {
|
||||
|
||||
public TransientProperties() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark any additional properties as transient.
|
||||
*/
|
||||
public void process(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
List<DeployBeanProperty> props = desc.propertiesBase();
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
DeployBeanProperty prop = props.get(i);
|
||||
if (!prop.isDbRead() && !prop.isDbInsertable() && !prop.isDbUpdateable()) {
|
||||
// non-transient...
|
||||
prop.setTransient(true);
|
||||
}
|
||||
}
|
||||
|
||||
List<DeployBeanPropertyAssocOne<?>> ones = desc.propertiesAssocOne();
|
||||
for (int i = 0; i < ones.size(); i++) {
|
||||
DeployBeanPropertyAssocOne<?> prop = ones.get(i);
|
||||
if (prop.getBeanTable() == null) {
|
||||
if (!prop.isEmbedded()) {
|
||||
prop.setTransient(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<DeployBeanPropertyAssocMany<?>> manys = desc.propertiesAssocMany();
|
||||
for (int i = 0; i < manys.size(); i++) {
|
||||
DeployBeanPropertyAssocMany<?> prop = manys.get(i);
|
||||
if (prop.getBeanTable() == null) {
|
||||
prop.setTransient(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user