mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1b7774a23 | ||
|
|
c6632bbc25 | ||
|
|
8c12fc762c | ||
|
|
8cb0b13ccb | ||
|
|
c2faffb6f4 | ||
|
|
e17d823c17 | ||
|
|
9bf9338ba9 | ||
|
|
0da764ed0c | ||
|
|
43003f4a3a | ||
|
|
7081d3f54a | ||
|
|
cce2c2e28f | ||
|
|
61ecf16978 | ||
|
|
9ff4e63c32 | ||
|
|
a13fd55f64 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.6.1</version>
|
||||
<version>4.6.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
|
||||
@@ -69,7 +69,9 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
list.add((E) bean);
|
||||
if (bean != null) {
|
||||
list.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
@@ -154,7 +156,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanList ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
@@ -348,7 +350,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
Object o = it.next();
|
||||
if (list.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
@@ -366,7 +368,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
boolean changed = false;
|
||||
Iterator<E> it = list.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
Object o = it.next();
|
||||
if (!c.contains(o)) {
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
|
||||
@@ -52,12 +52,20 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPutNull() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPut(Object key, Object bean) {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
map.put((K)key, (E)bean);
|
||||
if (key != null) {
|
||||
map.put((K) key, (E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void internalAdd(Object bean) {
|
||||
|
||||
@@ -62,7 +62,9 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
set.add((E) bean);
|
||||
if (bean != null) {
|
||||
set.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,15 +145,8 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying set.
|
||||
*/
|
||||
public Object getActualCollection() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanSet ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
@@ -274,7 +269,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
Object o = it.next();
|
||||
if (set.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -29,364 +30,339 @@ import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
|
||||
*/
|
||||
public class BootupClasses implements ClassPathSearchMatcher {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);
|
||||
|
||||
private ArrayList<Class<?>> embeddableList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> embeddableList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> entityList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> entityList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarTypeList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> scalarTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> scalarConverterList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> scalarConverterList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> compoundTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanControllerList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> compoundTypeList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanControllerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
|
||||
|
||||
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
|
||||
public BootupClasses() {
|
||||
public BootupClasses() {
|
||||
}
|
||||
|
||||
public BootupClasses(List<Class<?>> list) {
|
||||
if (list != null) {
|
||||
for (Class<?> cls : list) {
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any ServerConfigStartup listeners.
|
||||
*/
|
||||
public void runServerConfigStartup(ServerConfig serverConfig) {
|
||||
|
||||
for (Class<?> cls : serverConfigStartupList) {
|
||||
try {
|
||||
ServerConfigStartup newInstance = (ServerConfigStartup) cls.newInstance();
|
||||
newInstance.onStart(serverConfig);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addQueryAdapters(List<BeanQueryAdapter> queryAdapterInstances) {
|
||||
if (queryAdapterInstances != null) {
|
||||
for (BeanQueryAdapter a : queryAdapterInstances) {
|
||||
this.queryAdapterInstances.add(a);
|
||||
// don't automatically instantiate
|
||||
this.beanQueryAdapterList.remove(a.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BeanPersistController instances.
|
||||
*/
|
||||
public void addPersistControllers(List<BeanPersistController> beanControllerInstances) {
|
||||
if (beanControllerInstances != null) {
|
||||
for (BeanPersistController c : beanControllerInstances) {
|
||||
this.persistControllerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.beanControllerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TransactionEventListeners instances.
|
||||
*/
|
||||
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
if (transactionEventListeners != null) {
|
||||
for (TransactionEventListener c : transactionEventListeners) {
|
||||
this.transactionEventListenerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.transactionEventListenerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addServerConfigStartup(List<ServerConfigStartup> startupInstances) {
|
||||
if (startupInstances != null) {
|
||||
for (ServerConfigStartup l : startupInstances) {
|
||||
this.serverConfigStartupInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.serverConfigStartupList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<BeanQueryAdapter> getBeanQueryAdapters() {
|
||||
// add class registered BeanQueryAdapter to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanQueryAdapterList) {
|
||||
try {
|
||||
BeanQueryAdapter newInstance = (BeanQueryAdapter) cls.newInstance();
|
||||
queryAdapterInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
public BootupClasses(List<Class<?>> list) {
|
||||
if (list != null) {
|
||||
for (Class<?> cls : list) {
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
return queryAdapterInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
private BootupClasses(BootupClasses parent) {
|
||||
this.embeddableList.addAll(parent.embeddableList);
|
||||
this.entityList.addAll(parent.entityList);
|
||||
this.scalarTypeList.addAll(parent.scalarTypeList);
|
||||
this.scalarConverterList.addAll(parent.scalarConverterList);
|
||||
this.compoundTypeList.addAll(parent.compoundTypeList);
|
||||
this.beanControllerList.addAll(parent.beanControllerList);
|
||||
this.transactionEventListenerList.addAll(parent.transactionEventListenerList);
|
||||
this.beanFinderList.addAll(parent.beanFinderList);
|
||||
this.beanListenerList.addAll(parent.beanListenerList);
|
||||
this.beanQueryAdapterList.addAll(parent.beanQueryAdapterList);
|
||||
this.serverConfigStartupList.addAll(parent.serverConfigStartupList);
|
||||
return persistListenerInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistController> getBeanPersistControllers() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanControllerList) {
|
||||
try {
|
||||
BeanPersistController newInstance = (BeanPersistController) cls.newInstance();
|
||||
persistControllerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this object so that classes can be added to it.
|
||||
*/
|
||||
public BootupClasses createCopy() {
|
||||
return new BootupClasses(this);
|
||||
return persistControllerInstances;
|
||||
}
|
||||
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
// add class registered TransactionEventListener to the
|
||||
// already created instances
|
||||
for (Class<?> cls : transactionEventListenerList) {
|
||||
try {
|
||||
TransactionEventListener newInstance = (TransactionEventListener) cls.newInstance();
|
||||
transactionEventListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating TransactionEventListener " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run any ServerConfigStartup listeners.
|
||||
*/
|
||||
public void runServerConfigStartup(ServerConfig serverConfig) {
|
||||
|
||||
for (Class<?> cls : serverConfigStartupList) {
|
||||
try {
|
||||
ServerConfigStartup newInstance = (ServerConfigStartup) cls.newInstance();
|
||||
newInstance.onStart(serverConfig);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addQueryAdapters(List<BeanQueryAdapter> queryAdapterInstances) {
|
||||
if (queryAdapterInstances != null) {
|
||||
for (BeanQueryAdapter a : queryAdapterInstances) {
|
||||
this.queryAdapterInstances.add(a);
|
||||
// don't automatically instantiate
|
||||
this.beanQueryAdapterList.remove(a.getClass());
|
||||
}
|
||||
}
|
||||
return transactionEventListenerInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Embeddable classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEmbeddables() {
|
||||
return embeddableList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of entity classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEntities() {
|
||||
return entityList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarTypes found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarTypes() {
|
||||
return scalarTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarConverters() {
|
||||
return scalarConverterList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getCompoundTypes() {
|
||||
return compoundTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanControllers found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanControllers() {
|
||||
return beanControllerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of TransactionEventListeners found
|
||||
*/
|
||||
public ArrayList<Class<?>> getTransactionEventListenerList() {
|
||||
return transactionEventListenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanFinders found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanFinders() {
|
||||
return beanFinderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanListeners found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanListeners() {
|
||||
return beanListenerList;
|
||||
}
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
if (isEmbeddable(cls)) {
|
||||
embeddableList.add(cls);
|
||||
|
||||
} else if (isEntity(cls)) {
|
||||
entityList.add(cls);
|
||||
|
||||
} else {
|
||||
return isInterestingInterface(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BeanPersistController instances.
|
||||
*/
|
||||
public void addPersistControllers(List<BeanPersistController> beanControllerInstances) {
|
||||
if (beanControllerInstances != null) {
|
||||
for (BeanPersistController c : beanControllerInstances) {
|
||||
this.persistControllerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.beanControllerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for interesting interfaces.
|
||||
* <p>
|
||||
* This includes ScalarType, BeanController, BeanFinder and BeanListener.
|
||||
* </p>
|
||||
*/
|
||||
private boolean isInterestingInterface(Class<?> cls) {
|
||||
|
||||
if (Modifier.isAbstract(cls.getModifiers())) {
|
||||
// do not include abstract classes as we can
|
||||
// not instantiate them
|
||||
return false;
|
||||
}
|
||||
boolean interesting = false;
|
||||
|
||||
if (BeanPersistController.class.isAssignableFrom(cls)) {
|
||||
beanControllerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TransactionEventListeners instances.
|
||||
*/
|
||||
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
if (transactionEventListeners != null) {
|
||||
for (TransactionEventListener c : transactionEventListeners) {
|
||||
this.transactionEventListenerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.transactionEventListenerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
if (TransactionEventListener.class.isAssignableFrom(cls)) {
|
||||
transactionEventListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addServerConfigStartup(List<ServerConfigStartup> startupInstances) {
|
||||
if (startupInstances != null) {
|
||||
for (ServerConfigStartup l : startupInstances) {
|
||||
this.serverConfigStartupInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.serverConfigStartupList.remove(l.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<BeanQueryAdapter> getBeanQueryAdapters() {
|
||||
// add class registered BeanQueryAdapter to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanQueryAdapterList) {
|
||||
try {
|
||||
BeanQueryAdapter newInstance = (BeanQueryAdapter) cls.newInstance();
|
||||
queryAdapterInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanQueryAdapter " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return queryAdapterInstances;
|
||||
if (ScalarType.class.isAssignableFrom(cls)) {
|
||||
scalarTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistListenerInstances;
|
||||
if (ScalarTypeConverter.class.isAssignableFrom(cls)) {
|
||||
scalarConverterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public List<BeanPersistController> getBeanPersistControllers() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanControllerList) {
|
||||
try {
|
||||
BeanPersistController newInstance = (BeanPersistController) cls.newInstance();
|
||||
persistControllerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return persistControllerInstances;
|
||||
if (CompoundType.class.isAssignableFrom(cls)) {
|
||||
compoundTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
// add class registered TransactionEventListener to the
|
||||
// already created instances
|
||||
for (Class<?> cls : transactionEventListenerList) {
|
||||
try {
|
||||
TransactionEventListener newInstance = (TransactionEventListener) cls.newInstance();
|
||||
transactionEventListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating TransactionEventListener " + cls;
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return transactionEventListenerInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Embeddable classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEmbeddables() {
|
||||
return embeddableList;
|
||||
if (BeanFinder.class.isAssignableFrom(cls)) {
|
||||
beanFinderList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of entity classes.
|
||||
*/
|
||||
public ArrayList<Class<?>> getEntities() {
|
||||
return entityList;
|
||||
if (BeanPersistListener.class.isAssignableFrom(cls)) {
|
||||
beanListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarTypes found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarTypes() {
|
||||
return scalarTypeList;
|
||||
if (BeanQueryAdapter.class.isAssignableFrom(cls)) {
|
||||
beanQueryAdapterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getScalarConverters() {
|
||||
return scalarConverterList;
|
||||
if (ServerConfigStartup.class.isAssignableFrom(cls)) {
|
||||
serverConfigStartupList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of ScalarConverters found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getCompoundTypes() {
|
||||
return compoundTypeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanControllers found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanControllers() {
|
||||
return beanControllerList;
|
||||
return interesting;
|
||||
}
|
||||
|
||||
private boolean isEntity(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Entity.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(Table.class);
|
||||
return ann != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of TransactionEventListeners found
|
||||
*/
|
||||
public ArrayList<Class<?>> getTransactionEventListenerList() {
|
||||
return transactionEventListenerList;
|
||||
}
|
||||
private boolean isEmbeddable(Class<?> cls) {
|
||||
|
||||
/**
|
||||
* Return the list of BeanFinders found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanFinders() {
|
||||
return beanFinderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanListeners found.
|
||||
*/
|
||||
public ArrayList<Class<?>> getBeanListeners() {
|
||||
return beanListenerList;
|
||||
}
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
if (isEmbeddable(cls)) {
|
||||
embeddableList.add(cls);
|
||||
|
||||
} else if (isEntity(cls)) {
|
||||
entityList.add(cls);
|
||||
|
||||
} else if (isInterestingInterface(cls)) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for interesting interfaces.
|
||||
* <p>
|
||||
* This includes ScalarType, BeanController, BeanFinder and BeanListener.
|
||||
* </p>
|
||||
*/
|
||||
private boolean isInterestingInterface(Class<?> cls) {
|
||||
|
||||
boolean interesting = false;
|
||||
|
||||
if (BeanPersistController.class.isAssignableFrom(cls)) {
|
||||
beanControllerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (TransactionEventListener.class.isAssignableFrom(cls)) {
|
||||
transactionEventListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarType.class.isAssignableFrom(cls)) {
|
||||
scalarTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarTypeConverter.class.isAssignableFrom(cls)) {
|
||||
scalarConverterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (CompoundType.class.isAssignableFrom(cls)) {
|
||||
compoundTypeList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanFinder.class.isAssignableFrom(cls)) {
|
||||
beanFinderList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanPersistListener.class.isAssignableFrom(cls)) {
|
||||
beanListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanQueryAdapter.class.isAssignableFrom(cls)) {
|
||||
beanQueryAdapterList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ServerConfigStartup.class.isAssignableFrom(cls)){
|
||||
serverConfigStartupList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
return interesting;
|
||||
}
|
||||
|
||||
private boolean isEntity(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Entity.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(Table.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isEmbeddable(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Embeddable.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Annotation ann = cls.getAnnotation(Embeddable.class);
|
||||
return ann != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,18 +104,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
|
||||
private final boolean autoFetchTunable;
|
||||
|
||||
private final String lazyFetchIncludes;
|
||||
|
||||
/**
|
||||
* The concurrency mode for beans of this type.
|
||||
*/
|
||||
private final ConcurrencyMode concurrencyMode;
|
||||
|
||||
/**
|
||||
* The tables this bean is dependent on.
|
||||
*/
|
||||
private final String[] dependantTables;
|
||||
|
||||
private final CompoundUniqueContraint[] compoundUniqueConstraints;
|
||||
|
||||
/**
|
||||
@@ -127,7 +120,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Map of BeanProperty Linked so as to preserve order.
|
||||
*/
|
||||
private final LinkedHashMap<String, BeanProperty> propMap;
|
||||
private final LinkedHashMap<String, BeanProperty> propMapByDbColumn;
|
||||
|
||||
/**
|
||||
* The type of bean this describes.
|
||||
@@ -222,7 +214,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneImportedSave;
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneImportedDelete;
|
||||
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneExported;
|
||||
//private final BeanPropertyAssocOne<?>[] propertiesOneExported;
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneExportedSave;
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneExportedDelete;
|
||||
|
||||
@@ -339,11 +331,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.sequenceInitialValue = deploy.getSequenceInitialValue();
|
||||
this.sequenceAllocationSize = deploy.getSequenceAllocationSize();
|
||||
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
|
||||
this.lazyFetchIncludes = InternString.intern(deploy.getLazyFetchIncludes());
|
||||
this.concurrencyMode = deploy.getConcurrencyMode();
|
||||
this.updateChangesOnly = deploy.isUpdateChangesOnly();
|
||||
|
||||
this.dependantTables = deploy.getDependantTables();
|
||||
this.compoundUniqueConstraints = deploy.getCompoundUniqueConstraints();
|
||||
|
||||
this.baseTable = InternString.intern(deploy.getBaseTable());
|
||||
@@ -356,7 +345,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.idProperty = listHelper.getId();
|
||||
this.versionProperty = listHelper.getVersionProperty();
|
||||
this.propMap = listHelper.getPropertyMap();
|
||||
this.propMapByDbColumn = getReverseMap(propMap);
|
||||
this.propertiesTransient = listHelper.getTransients();
|
||||
this.propertiesNonTransient = listHelper.getNonTransients();
|
||||
this.propertiesBaseScalar = listHelper.getBaseScalar();
|
||||
@@ -366,7 +354,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.propertiesMutable = listHelper.getMutable();
|
||||
this.unidirectional = listHelper.getUnidirectional();
|
||||
this.propertiesOne = listHelper.getOnes();
|
||||
this.propertiesOneExported = listHelper.getOneExported();
|
||||
//this.propertiesOneExported = listHelper.getOneExported();
|
||||
this.propertiesOneExportedSave = listHelper.getOneExportedSave();
|
||||
this.propertiesOneExportedDelete = listHelper.getOneExportedDelete();
|
||||
this.propertiesOneImported = listHelper.getOneImported();
|
||||
@@ -649,10 +637,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return (queryUseCache != null) ? queryUseCache.booleanValue() : isBeanCaching();
|
||||
}
|
||||
|
||||
public T cacheNaturalKey(SpiQuery<T> query, SpiTransaction t) {
|
||||
return cacheHelp.naturalKeyLookup(query, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache options.
|
||||
*/
|
||||
@@ -718,13 +702,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
cacheHelp.setUseCache(useCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently query caching for this type of bean.
|
||||
*/
|
||||
public boolean isQueryCaching() {
|
||||
return cacheHelp.isQueryCaching();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently bean caching for this type of bean.
|
||||
*/
|
||||
@@ -786,20 +763,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
cacheHelp.manyPropClear(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CachedManyIds for a given bean and property. Returns null if not in the cache.
|
||||
*/
|
||||
public CachedManyIds cacheManyPropGet(Object parentId, String propertyName) {
|
||||
return cacheHelp.manyPropGet(parentId, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the bean cache.
|
||||
*/
|
||||
public void cacheBeanClear() {
|
||||
cacheHelp.beanCacheClear();
|
||||
}
|
||||
|
||||
public void cacheBeanPut(T bean) {
|
||||
cacheBeanPutData((EntityBean)bean);
|
||||
}
|
||||
@@ -1534,14 +1497,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return EntityType.EMBEDDED.equals(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tables this bean is dependent on. This implies that if any of
|
||||
* these tables are modified then cached beans may be invalidated.
|
||||
*/
|
||||
public String[] getDependantTables() {
|
||||
return dependantTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the compound unique constraints.
|
||||
*/
|
||||
@@ -1570,26 +1525,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return queryAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register the BeanPersistListener.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void deregister(BeanPersistListener listener) {
|
||||
// volatile read...
|
||||
BeanPersistListener currListener = persistListener;
|
||||
if (currListener == null) {
|
||||
// nothing to deregister
|
||||
} else {
|
||||
BeanPersistListener deregListener = listener;
|
||||
if (currListener instanceof ChainedBeanPersistListener) {
|
||||
// remove it from the existing chain
|
||||
persistListener = ((ChainedBeanPersistListener) currListener).deregister(deregListener);
|
||||
} else if (currListener.equals(deregListener)) {
|
||||
persistListener = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register the BeanPersistController.
|
||||
*/
|
||||
@@ -1717,20 +1652,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return selectLastInsertedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IdGenerator.
|
||||
*/
|
||||
public IdGenerator getIdGenerator() {
|
||||
return idGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the includes for getReference().
|
||||
*/
|
||||
public String getLazyFetchIncludes() {
|
||||
return lazyFetchIncludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TableJoins.
|
||||
* <p>
|
||||
@@ -1823,14 +1744,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
public void checkMutableProperties(EntityBeanIntercept ebi) {
|
||||
for (int i = 0; i < propertiesMutable.length; i++) {
|
||||
BeanProperty beanProperty = propertiesMutable[i];
|
||||
if (ebi.isDirtyProperty(beanProperty.getPropertyIndex())) {
|
||||
// already marked as dirty
|
||||
} else if (ebi.isLoadedProperty(beanProperty.getPropertyIndex())) {
|
||||
int propertyIndex = beanProperty.getPropertyIndex();
|
||||
if (!ebi.isDirtyProperty(propertyIndex) && ebi.isLoadedProperty(propertyIndex)) {
|
||||
Object value = beanProperty.getValue(ebi.getOwner());
|
||||
if (value == null || beanProperty.isDirtyValue(value)) {
|
||||
// mutable scalar value which is considered dirty so mark
|
||||
// it as such so that it is included in an update
|
||||
ebi.markPropertyAsChanged(beanProperty.getPropertyIndex());
|
||||
ebi.markPropertyAsChanged(propertyIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private List<BeanDescriptor<?>> immutableDescriptorList;
|
||||
|
||||
private final Set<Integer> descriptorUniqueIds = new HashSet<Integer>();
|
||||
|
||||
private final DbIdentity dbIdentity;
|
||||
|
||||
private final DataSource dataSource;
|
||||
@@ -286,9 +284,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
for (BeanDescriptor<?> desc : descMap.values()) {
|
||||
String baseTable = desc.getBaseTable();
|
||||
if (baseTable == null) {
|
||||
|
||||
} else {
|
||||
if (baseTable != null) {
|
||||
baseTable = baseTable.toLowerCase();
|
||||
|
||||
List<BeanDescriptor<?>> list = tableToDescMap.get(baseTable);
|
||||
@@ -363,8 +359,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
BeanDescriptor<?> idBeanDescriptor = embId.getIdBeanDescriptor();
|
||||
Class<?> idType = idBeanDescriptor.getBeanType();
|
||||
try {
|
||||
idType.getDeclaredMethod("hashCode", new Class[] {});
|
||||
idType.getDeclaredMethod("equals", new Class[] { Object.class });
|
||||
idType.getDeclaredMethod("hashCode");
|
||||
idType.getDeclaredMethod("equals", Object.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
checkMissingHashCodeOrEquals(e, idType, d.getBeanType());
|
||||
}
|
||||
@@ -385,18 +381,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
return immutableDescriptorList;
|
||||
}
|
||||
|
||||
public Map<Class<?>, BeanTable> getBeanTables() {
|
||||
return beanTableMap;
|
||||
}
|
||||
|
||||
public BeanTable getBeanTable(Class<?> type) {
|
||||
return beanTableMap.get(type);
|
||||
}
|
||||
|
||||
public Map<String, BeanDescriptor<?>> getBeanDescriptors() {
|
||||
return descMap;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanManager<T> getBeanManager(Class<T> entityType) {
|
||||
|
||||
@@ -539,9 +527,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
BeanDescriptor<?> desc = getBeanDescriptor(deployDesc.getBeanType());
|
||||
|
||||
for (DRawSqlMeta rawSqlMeta : deployDesc.getRawSqlMeta()) {
|
||||
if (rawSqlMeta.getQuery() == null) {
|
||||
|
||||
} else {
|
||||
if (rawSqlMeta.getQuery() != null) {
|
||||
DeployNamedQuery nq = new DRawSqlSelectBuilder(namingConvention, desc, rawSqlMeta).parse();
|
||||
desc.addNamedQuery(nq);
|
||||
}
|
||||
@@ -603,15 +589,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private Integer getUniqueHash(DeployBeanDescriptor<?> deployBeanDescriptor) {
|
||||
|
||||
int hashCode = deployBeanDescriptor.getFullName().hashCode();
|
||||
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
Integer key = Integer.valueOf(hashCode + i);
|
||||
if (!descriptorUniqueIds.contains(key)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Failed to generate a unique hash for " + deployBeanDescriptor.getFullName());
|
||||
return deployBeanDescriptor.getFullName().hashCode();
|
||||
}
|
||||
|
||||
private void secondaryPropsJoins(DeployBeanInfo<?> info) {
|
||||
@@ -646,7 +624,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
|
||||
if (!oneProp.isTransient()) {
|
||||
if (oneProp.getMappedBy() != null) {
|
||||
checkMappedByOneToOne(info, oneProp);
|
||||
checkMappedByOneToOne(oneProp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -654,7 +632,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
|
||||
if (!manyProp.isTransient()) {
|
||||
if (manyProp.isManyToMany()) {
|
||||
checkMappedByManyToMany(info, manyProp);
|
||||
checkMappedByManyToMany(manyProp);
|
||||
} else {
|
||||
checkMappedByOneToMany(info, manyProp);
|
||||
}
|
||||
@@ -724,7 +702,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
// search for this in the possible matches
|
||||
for (String possibleMappedBy : matchSet) {
|
||||
String possibleLower = possibleMappedBy.toLowerCase();
|
||||
if (possibleLower.indexOf(searchName) > -1) {
|
||||
if (possibleLower.contains(searchName)) {
|
||||
// we have a match..
|
||||
prop.setMappedBy(possibleMappedBy);
|
||||
|
||||
@@ -809,7 +787,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
}
|
||||
|
||||
private void checkMappedByOneToOne(DeployBeanInfo<?> info, DeployBeanPropertyAssocOne<?> prop) {
|
||||
private void checkMappedByOneToOne(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
// check that the mappedBy property is valid and read
|
||||
// its associated join information if it is available
|
||||
@@ -901,7 +879,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
/**
|
||||
* For mappedBy copy the joins from the other side.
|
||||
*/
|
||||
private void checkMappedByManyToMany(DeployBeanInfo<?> info, DeployBeanPropertyAssocMany<?> prop) {
|
||||
private void checkMappedByManyToMany(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
// get the bean descriptor that holds the mappedBy property
|
||||
String mappedBy = prop.getMappedBy();
|
||||
@@ -1029,10 +1007,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private <T> IdType setIdGeneration(DeployBeanDescriptor<T> desc) {
|
||||
|
||||
if (desc.propertiesId().size() == 0) {
|
||||
// bean doen't have an Id property
|
||||
if (!desc.isBaseTableType() || desc.getBeanFinder() != null) {
|
||||
// using BeanFinder so perhaps valid without an id
|
||||
} else {
|
||||
// bean doesn't have an Id property
|
||||
if (desc.isBaseTableType() && desc.getBeanFinder() == null) {
|
||||
// expecting an id property
|
||||
logger.warn(Message.msg("deploy.nouid", desc.getFullName()));
|
||||
}
|
||||
@@ -1120,7 +1096,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private void setScalarType(DeployBeanDescriptor<?> deployDesc) {
|
||||
|
||||
for (DeployBeanProperty prop : deployDesc.propertiesAll()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?> == false) {
|
||||
if (!(prop instanceof DeployBeanPropertyAssoc<?>)) {
|
||||
deployUtil.setScalarType(prop);
|
||||
}
|
||||
}
|
||||
@@ -1228,7 +1204,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
for (Dnode namedQueryXml : namedQueries) {
|
||||
|
||||
String name = (String) namedQueryXml.getAttribute("name");
|
||||
String name = namedQueryXml.getAttribute("name");
|
||||
Dnode query = namedQueryXml.find("query");
|
||||
if (query == null) {
|
||||
logger.warn("orm.xml " + deployDesc.getFullName() + " named-query missing query element?");
|
||||
@@ -1271,7 +1247,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
BeanPropertiesReader reflectProps = new BeanPropertiesReader(beanType);
|
||||
|
||||
BeanPropertyInfo beanReflect = reflectFactory.create(beanType);
|
||||
desc.setBeanReflect(beanReflect);
|
||||
desc.setProperties(reflectProps.getProperties());
|
||||
|
||||
for (DeployBeanProperty prop : desc.propertiesAll()) {
|
||||
@@ -1283,7 +1258,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
} else {
|
||||
int propertyIndex = pos.intValue();
|
||||
final int propertyIndex = pos;
|
||||
prop.setPropertyIndex(propertyIndex);
|
||||
prop.setGetter(beanReflect.getGetter(propName, propertyIndex));
|
||||
prop.setSetter(beanReflect.getSetter(propName, propertyIndex));
|
||||
@@ -1295,16 +1270,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Return true if this is a persistent field (not transient or static).
|
||||
*/
|
||||
private boolean isPersistentField(DeployBeanProperty prop) {
|
||||
|
||||
|
||||
Field field = prop.getField();
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) {
|
||||
return false;
|
||||
}
|
||||
if (field.isAnnotationPresent(Transient.class)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !(Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) && !field.isAnnotationPresent(Transient.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -109,8 +109,12 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
|
||||
if (bean == null) {
|
||||
((BeanMap<?, ?>) collection).internalPutNull();
|
||||
} else {
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -181,16 +181,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
*/
|
||||
final Map<String, String> extraAttributeMap;
|
||||
|
||||
/**
|
||||
* The method used to read the property.
|
||||
*/
|
||||
final Method readMethod;
|
||||
|
||||
/**
|
||||
* The method used to write the property.
|
||||
*/
|
||||
final Method writeMethod;
|
||||
|
||||
/**
|
||||
* Generator for insert or update timestamp etc.
|
||||
*/
|
||||
@@ -290,8 +280,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
this.embedded = deploy.isEmbedded();
|
||||
this.id = deploy.isId();
|
||||
this.generatedProperty = deploy.getGeneratedProperty();
|
||||
this.readMethod = deploy.getReadMethod();
|
||||
this.writeMethod = deploy.getWriteMethod();
|
||||
this.getter = deploy.getGetter();
|
||||
this.setter = deploy.getSetter();
|
||||
|
||||
@@ -382,8 +370,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
this.embedded = source.isEmbedded();
|
||||
this.id = source.isId();
|
||||
this.generatedProperty = source.getGeneratedProperty();
|
||||
this.readMethod = source.getReadMethod();
|
||||
this.writeMethod = source.getWriteMethod();
|
||||
this.getter = source.getter;
|
||||
this.setter = source.setter;
|
||||
this.extraAttributeMap = source.extraAttributeMap;
|
||||
@@ -609,20 +595,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the getter method.
|
||||
*/
|
||||
public Method getReadMethod() {
|
||||
return readMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the setter method.
|
||||
*/
|
||||
public Method getWriteMethod() {
|
||||
return writeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this object is part of an inheritance hierarchy.
|
||||
*/
|
||||
|
||||
@@ -17,18 +17,11 @@ import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
* 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;
|
||||
|
||||
@@ -42,7 +35,6 @@ public class BeanPropertyCompoundRoot {
|
||||
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>();
|
||||
}
|
||||
@@ -75,13 +67,7 @@ public class BeanPropertyCompoundRoot {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
setter.set(bean, value);
|
||||
} 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";
|
||||
@@ -94,13 +80,7 @@ public class BeanPropertyCompoundRoot {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
setter.setIntercept(bean, value);
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "setIntercept " + name + " arg[" + value + "] on ["+fullBeanName+"] with type[" + beanType + "] threw error";
|
||||
|
||||
@@ -13,75 +13,70 @@ import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
* Context provided when a BeanProperty reads from a ResultSet.
|
||||
*/
|
||||
public interface DbReadContext {
|
||||
|
||||
|
||||
/**
|
||||
* Return the state of the object graph.
|
||||
*/
|
||||
public Boolean isReadOnly();
|
||||
|
||||
Boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Propagate the state to the bean.
|
||||
*/
|
||||
public void propagateState(Object e);
|
||||
|
||||
void propagateState(Object e);
|
||||
|
||||
/**
|
||||
* Return the DataReader.
|
||||
*/
|
||||
public DataReader getDataReader();
|
||||
|
||||
/**
|
||||
* Return true if the query is using supplied SQL rather than generated SQL.
|
||||
*/
|
||||
public boolean isRawSql();
|
||||
|
||||
/**
|
||||
* Set the JoinNode - used by proxy/reference beans for profiling.
|
||||
*/
|
||||
public void setCurrentPrefix(String currentPrefix, Map<String,String> pathMap);
|
||||
DataReader getDataReader();
|
||||
|
||||
/**
|
||||
* Return true if we are profiling this query.
|
||||
*/
|
||||
public boolean isAutoFetchProfiling();
|
||||
|
||||
/**
|
||||
* Add autoFetch profiling for a loaded entity bean.
|
||||
*/
|
||||
public void profileBean(EntityBeanIntercept ebi, String prefix);
|
||||
|
||||
/**
|
||||
* Return the persistence context.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
/**
|
||||
* Return true if the query is using supplied SQL rather than generated SQL.
|
||||
*/
|
||||
boolean isRawSql();
|
||||
|
||||
/**
|
||||
* Register a reference for lazy loading.
|
||||
*/
|
||||
public void register(String path, EntityBeanIntercept ebi);
|
||||
/**
|
||||
* Set the JoinNode - used by proxy/reference beans for profiling.
|
||||
*/
|
||||
void setCurrentPrefix(String currentPrefix, Map<String, String> pathMap);
|
||||
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
public void register(String path, BeanCollection<?> bc);
|
||||
/**
|
||||
* Return true if we are profiling this query.
|
||||
*/
|
||||
boolean isAutoFetchProfiling();
|
||||
|
||||
/**
|
||||
* Return the property that is associated with the many. There can only be
|
||||
* one. This can be null.
|
||||
*/
|
||||
public BeanPropertyAssocMany<?> getManyProperty();
|
||||
/**
|
||||
* Add autoFetch profiling for a loaded entity bean.
|
||||
*/
|
||||
void profileBean(EntityBeanIntercept ebi, String prefix);
|
||||
|
||||
/**
|
||||
* Set back the bean that has just been loaded with its id.
|
||||
*/
|
||||
public void setLoadedBean(EntityBean loadedBean, Object id, Object lazyLoadParentId);
|
||||
/**
|
||||
* Return the persistence context.
|
||||
*/
|
||||
PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Set back the 'detail' bean that has just been loaded.
|
||||
*/
|
||||
public void setLoadedManyBean(EntityBean loadedBean);
|
||||
|
||||
/**
|
||||
* Return the query mode.
|
||||
*/
|
||||
public SpiQuery.Mode getQueryMode();
|
||||
/**
|
||||
* Register a reference for lazy loading.
|
||||
*/
|
||||
void register(String path, EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Register a collection for lazy loading.
|
||||
*/
|
||||
void register(String path, BeanCollection<?> bc);
|
||||
|
||||
/**
|
||||
* Return the property that is associated with the many. There can only be
|
||||
* one. This can be null.
|
||||
*/
|
||||
BeanPropertyAssocMany<?> getManyProperty();
|
||||
|
||||
/**
|
||||
* Set back the bean that has just been loaded with its id.
|
||||
*/
|
||||
void setLazyLoadedChildBean(EntityBean loadedBean, Object parentId);
|
||||
|
||||
/**
|
||||
* Return the query mode.
|
||||
*/
|
||||
SpiQuery.Mode getQueryMode();
|
||||
}
|
||||
|
||||
+10
-159
@@ -1,23 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.ConcurrencyMode;
|
||||
import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebean.config.dbplatform.IdGenerator;
|
||||
@@ -28,16 +10,14 @@ import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistController;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistListener;
|
||||
import com.avaje.ebeaninternal.server.deploy.ChainedBeanQueryAdapter;
|
||||
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint;
|
||||
import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.*;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfo;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Describes Beans including their deployment information.
|
||||
*/
|
||||
@@ -57,8 +37,6 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private static final String I_SCALAOBJECT = "scala.ScalaObject";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeployBeanDescriptor.class);
|
||||
|
||||
/**
|
||||
* Map of BeanProperty Linked so as to preserve order.
|
||||
*/
|
||||
@@ -100,8 +78,6 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
private String selectLastInsertedId;
|
||||
|
||||
private String lazyFetchIncludes;
|
||||
|
||||
/**
|
||||
* The concurrency mode for beans of this type.
|
||||
*/
|
||||
@@ -109,11 +85,6 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private boolean updateChangesOnly;
|
||||
|
||||
/**
|
||||
* The tables this bean is dependent on.
|
||||
*/
|
||||
private String[] dependantTables;
|
||||
|
||||
private List<CompoundUniqueContraint> compoundUniqueConstraints;
|
||||
|
||||
/**
|
||||
@@ -122,11 +93,6 @@ public class DeployBeanDescriptor<T> {
|
||||
private String baseTable;
|
||||
private TableName baseTableFull;
|
||||
|
||||
/**
|
||||
* Used to provide mechanism to new EntityBean instances. Generated code
|
||||
* faster than reflection at this stage.
|
||||
*/
|
||||
private BeanPropertyInfo beanReflect;
|
||||
private String[] properties;
|
||||
|
||||
/**
|
||||
@@ -219,34 +185,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return beanTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all the properties to see if they all have read and write methods
|
||||
* (required if using "subclassing" but not for "enhancement").
|
||||
*/
|
||||
public boolean checkReadAndWriteMethods() {
|
||||
|
||||
boolean missingMethods = false;
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (!prop.isTransient()) {
|
||||
String m = "";
|
||||
if (prop.getReadMethod() == null) {
|
||||
m += " missing readMethod ";
|
||||
}
|
||||
if (prop.getWriteMethod() == null) {
|
||||
m += " missing writeMethod ";
|
||||
}
|
||||
if (!"".equals(m)) {
|
||||
m += ". Should it be transient?";
|
||||
String msg = "Bean property " + getFullName() + "." + prop.getName() + " has " + m;
|
||||
logger.error(msg);
|
||||
missingMethods = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !missingMethods;
|
||||
}
|
||||
|
||||
public void setEntityType(EntityType entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
@@ -317,10 +255,6 @@ public class DeployBeanDescriptor<T> {
|
||||
this.properties = props;
|
||||
}
|
||||
|
||||
public BeanPropertyInfo getBeanReflect() {
|
||||
return beanReflect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class type this BeanDescriptor describes.
|
||||
*/
|
||||
@@ -328,14 +262,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BeanReflect used to create new instances of an EntityBean. This
|
||||
* could use reflection or code generation to do this.
|
||||
*/
|
||||
public void setBeanReflect(BeanPropertyInfo beanReflect) {
|
||||
this.beanReflect = beanReflect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Inheritance mapping information. This will be null if this type
|
||||
* of bean is not involved in any ORM inheritance mapping.
|
||||
@@ -358,10 +284,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return cacheOptions;
|
||||
}
|
||||
|
||||
public boolean isNaturalKeyProperty(String name) {
|
||||
return name.equals(cacheOptions.getNaturalKey());
|
||||
}
|
||||
|
||||
public DeployBeanPropertyAssocOne<?> getUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
@@ -392,14 +314,6 @@ public class DeployBeanDescriptor<T> {
|
||||
this.updateChangesOnly = updateChangesOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tables this bean is dependant on. This implies that if any of
|
||||
* these tables are modified then cached beans may be invalidated.
|
||||
*/
|
||||
public String[] getDependantTables() {
|
||||
return dependantTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a compound unique constraint.
|
||||
*/
|
||||
@@ -421,14 +335,6 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tables this bean is dependant on. This implies that if any of these
|
||||
* tables are modified then cached beans may be invalidated.
|
||||
*/
|
||||
public void setDependantTables(String[] dependantTables) {
|
||||
this.dependantTables = dependantTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the beanFinder. Usually null unless overriding the finder.
|
||||
*/
|
||||
@@ -495,17 +401,6 @@ public class DeployBeanDescriptor<T> {
|
||||
queryAdapters.add(queryAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean type should use IdGeneration.
|
||||
* <p>
|
||||
* If this is false and the Id is null it is assumed that a database auto
|
||||
* increment feature is being used to populate the id.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isUseIdGenerator() {
|
||||
return idType == IdType.GENERATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table. Only properties mapped to the base table are by
|
||||
* default persisted.
|
||||
@@ -659,24 +554,6 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the includes for getReference().
|
||||
*/
|
||||
public String getLazyFetchIncludes() {
|
||||
return lazyFetchIncludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set includes to use for lazy loading by getReference(). Note queries also
|
||||
* build references and includes on the actual association are used for those
|
||||
* references.
|
||||
*/
|
||||
public void setLazyFetchIncludes(String lazyFetchIncludes) {
|
||||
if (lazyFetchIncludes != null && lazyFetchIncludes.length() > 0) {
|
||||
this.lazyFetchIncludes = lazyFetchIncludes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary description.
|
||||
*/
|
||||
@@ -712,11 +589,7 @@ public class DeployBeanDescriptor<T> {
|
||||
boolean hasLazyFetch = false;
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop.isTransient()) {
|
||||
// ignore transient props etc
|
||||
} else if (prop instanceof DeployBeanPropertyAssocMany<?>) {
|
||||
// ignore the associated many properties
|
||||
} else {
|
||||
if (!prop.isTransient() && !(prop instanceof DeployBeanPropertyAssocMany<?>)) {
|
||||
if (prop.isFetchEager()) {
|
||||
sb.append(prop.getName()).append(",");
|
||||
} else {
|
||||
@@ -748,7 +621,7 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
LinkedHashSet<String> set = new LinkedHashSet<String>(res.length + 3);
|
||||
|
||||
String temp = null;
|
||||
String temp;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
temp = res[i].trim();
|
||||
if (temp.length() > 0) {
|
||||
@@ -844,26 +717,6 @@ public class DeployBeanDescriptor<T> {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'Version' properties on this bean. These are 'Counter' or 'Update
|
||||
* Timestamp' type properties. Note version properties can also be on embedded
|
||||
* beans rather than on the bean itself.
|
||||
*/
|
||||
public List<DeployBeanProperty> propertiesVersion() {
|
||||
|
||||
ArrayList<DeployBeanProperty> list = new ArrayList<DeployBeanProperty>();
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?> == false) {
|
||||
if (!prop.isId() && prop.isVersionColumn()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* base properties without the unique id properties.
|
||||
*/
|
||||
@@ -872,10 +725,8 @@ public class DeployBeanDescriptor<T> {
|
||||
ArrayList<DeployBeanProperty> list = new ArrayList<DeployBeanProperty>();
|
||||
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop instanceof DeployBeanPropertyAssoc<?> == false) {
|
||||
if (!prop.isId()) {
|
||||
list.add(prop);
|
||||
}
|
||||
if (!(prop instanceof DeployBeanPropertyAssoc<?>) && !prop.isId()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,11 +195,6 @@ public class DeployBeanProperty {
|
||||
*/
|
||||
private Method readMethod;
|
||||
|
||||
/**
|
||||
* The method used to write the property.
|
||||
*/
|
||||
private Method writeMethod;
|
||||
|
||||
private int propertyIndex;
|
||||
|
||||
private BeanPropertyGetter getter;
|
||||
@@ -454,13 +449,6 @@ public class DeployBeanProperty {
|
||||
return readMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the setter method.
|
||||
*/
|
||||
public Method getWriteMethod() {
|
||||
return writeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to the owning type form a Inheritance heirarchy.
|
||||
*/
|
||||
@@ -850,17 +838,6 @@ public class DeployBeanProperty {
|
||||
this.readMethod = readMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean write method.
|
||||
* <p>
|
||||
* NB: That a BeanReflectSetter is used to actually perform the setting of
|
||||
* property values to a bean. This is due to performance considerations.
|
||||
* </p>
|
||||
*/
|
||||
public void setWriteMethod(Method writeMethod) {
|
||||
this.writeMethod = writeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property type.
|
||||
*/
|
||||
|
||||
+5
-28
@@ -56,20 +56,6 @@ public class DeployCreateProperties {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,13 +109,9 @@ public class DeployCreateProperties {
|
||||
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 {
|
||||
DeployBeanProperty prop = createProp(desc, field, beanType, getter);
|
||||
if (prop != null) {
|
||||
// set a order that gives priority to inherited properties
|
||||
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
|
||||
int sortOverride = prop.getSortOverride();
|
||||
@@ -264,7 +246,7 @@ public class DeployCreateProperties {
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, manyType);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("expected non-scalar type" + e.getMessage());
|
||||
logger.debug("expected non-scalar type {}", e.getMessage());
|
||||
}
|
||||
// TODO: Handle Collection of CompoundType and Embedded Type
|
||||
return new DeployBeanPropertyAssocMany(desc, targetType, manyType);
|
||||
@@ -282,7 +264,6 @@ public class DeployCreateProperties {
|
||||
|
||||
if (tt != null && !tt.equals(void.class)){
|
||||
propertyType = tt;
|
||||
logger.debug("target type" + tt);
|
||||
}
|
||||
}
|
||||
Class<?> innerType = propertyType;
|
||||
@@ -372,8 +353,7 @@ public class DeployCreateProperties {
|
||||
return (t != null);
|
||||
}
|
||||
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType,
|
||||
Method getter, Method setter) {
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType, Method getter) {
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field);
|
||||
if (prop == null) {
|
||||
@@ -383,11 +363,8 @@ public class DeployCreateProperties {
|
||||
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
|
||||
// interested in the getter for reading annotations
|
||||
prop.setReadMethod(getter);
|
||||
prop.setWriteMethod(setter);
|
||||
prop.setField(field);
|
||||
return prop;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQuery.class);
|
||||
|
||||
private static final int GLOBAL_ROW_LIMIT = Integer.valueOf(System.getProperty("ebean.query.globallimit","1000000"));
|
||||
private static final int GLOBAL_ROW_LIMIT = Integer.valueOf(System.getProperty("ebean.query.globallimit", "1000000"));
|
||||
|
||||
/**
|
||||
* The resultSet rows read.
|
||||
@@ -60,46 +60,22 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* Flag set when no more rows are in the resultSet.
|
||||
*/
|
||||
private boolean noMoreRows;
|
||||
/**
|
||||
* Id of loaded 'master' bean.
|
||||
*/
|
||||
private Object loadedBeanId;
|
||||
/**
|
||||
* Flag set when 'master' bean changed.
|
||||
*/
|
||||
private boolean loadedBeanChanged;
|
||||
|
||||
/**
|
||||
* The 'master' bean just loaded.
|
||||
*/
|
||||
private EntityBean loadedBean;
|
||||
private EntityBean nextBean;
|
||||
|
||||
/**
|
||||
* Holds the previous loaded bean.
|
||||
*/
|
||||
private EntityBean currentBean;
|
||||
|
||||
private final BeanPropertyAssocMany<?> lazyLoadManyProperty;
|
||||
|
||||
private Object lazyLoadParentId;
|
||||
|
||||
|
||||
private EntityBean lazyLoadParentBean;
|
||||
|
||||
/**
|
||||
* Holds the previous loaded bean.
|
||||
*/
|
||||
private EntityBean prevLoadedBean;
|
||||
|
||||
/**
|
||||
* The detail bean just loaded.
|
||||
*/
|
||||
private EntityBean loadedManyBean;
|
||||
|
||||
/**
|
||||
* The previous 'detail' collection remembered so that for manyToMany we can
|
||||
* turn on the modify listening.
|
||||
*/
|
||||
private Object prevDetailCollection;
|
||||
|
||||
/**
|
||||
* The current 'detail' collection being populated.
|
||||
*/
|
||||
private Object currentDetailCollection;
|
||||
|
||||
/**
|
||||
* The 'master' collection being populated.
|
||||
@@ -123,11 +99,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private String currentPrefix;
|
||||
|
||||
/**
|
||||
* Flag set true when reading 'master' and 'detail' beans.
|
||||
*/
|
||||
private final boolean manyIncluded;
|
||||
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
@@ -166,11 +137,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
*/
|
||||
private final BeanPropertyAssocMany<?> manyProperty;
|
||||
|
||||
/**
|
||||
* The many property Expression language object.
|
||||
*/
|
||||
private final ElPropertyValue manyPropertyEl;
|
||||
|
||||
private final int maxRowsLimit;
|
||||
|
||||
private DataReader dataReader;
|
||||
@@ -186,7 +152,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private final CQueryPlan queryPlan;
|
||||
|
||||
|
||||
private final Mode queryMode;
|
||||
|
||||
private final boolean autoFetchProfiling;
|
||||
@@ -194,20 +159,15 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
private final ObjectGraphNode objectGraphNode;
|
||||
|
||||
private final AutoFetchManager autoFetchManager;
|
||||
|
||||
|
||||
private final WeakReference<NodeUsageListener> autoFetchManagerRef;
|
||||
|
||||
|
||||
private final Boolean readOnly;
|
||||
|
||||
private final SpiExpressionList<?> filterMany;
|
||||
|
||||
private long startNano;
|
||||
|
||||
private long executionTimeMicros;
|
||||
|
||||
private BeanCollectionAdd currentDetailAdd;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
@@ -233,19 +193,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
this.sqlTree = queryPlan.getSqlTree();
|
||||
this.rootNode = sqlTree.getRootNode();
|
||||
|
||||
this.manyProperty = sqlTree.getManyProperty();
|
||||
this.manyPropertyEl = sqlTree.getManyPropertyEl();
|
||||
this.manyIncluded = sqlTree.isManyIncluded();
|
||||
if (manyIncluded) {
|
||||
// get filter to put on the collection for reuse with refresh
|
||||
String manyPropertyName = sqlTree.getManyPropertyName();
|
||||
OrmQueryProperties chunk = query.getDetail().getChunk(manyPropertyName, false);
|
||||
this.filterMany = (chunk == null) ? null : chunk.getFilterMany();
|
||||
} else {
|
||||
this.filterMany = null;
|
||||
}
|
||||
|
||||
this.sql = queryPlan.getSql();
|
||||
this.rawSql = queryPlan.isRawSql();
|
||||
this.rowNumberIncluded = queryPlan.isRowNumberIncluded();
|
||||
@@ -340,7 +288,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
// prepare
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
|
||||
|
||||
if (query.isRawSql()) {
|
||||
ResultSet suppliedResultSet = query.getRawSql().getResultSet();
|
||||
if (suppliedResultSet != null) {
|
||||
@@ -350,13 +298,13 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (forwardOnlyHint) {
|
||||
// Use forward only hints for large resultset processing (Issue 56, MySql specific)
|
||||
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
pstmt.setFetchSize(Integer.MIN_VALUE);
|
||||
} else {
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
}
|
||||
|
||||
if (query.getTimeout() > 0) {
|
||||
@@ -414,57 +362,17 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
return request.getPersistenceContext();
|
||||
}
|
||||
|
||||
public void setLoadedBean(EntityBean bean, Object id, Object lazyLoadParentId) {
|
||||
if (id != null && id.equals(loadedBeanId)) {
|
||||
// master/detail loading with master bean
|
||||
// unchanged. NB Using id to avoid any issue
|
||||
// with equals not being implemented
|
||||
public void setLazyLoadedChildBean(EntityBean bean, Object lazyLoadParentId) {
|
||||
|
||||
} else {
|
||||
if (manyIncluded) {
|
||||
if (rowCount > 1) {
|
||||
loadedBeanChanged = true;
|
||||
}
|
||||
this.prevLoadedBean = loadedBean;
|
||||
this.loadedBeanId = id;
|
||||
if (lazyLoadParentId != null) {
|
||||
if (!lazyLoadParentId.equals(this.lazyLoadParentId)) {
|
||||
// get the appropriate parent bean from the persistence context
|
||||
this.lazyLoadParentBean = (EntityBean) getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
|
||||
this.lazyLoadParentId = lazyLoadParentId;
|
||||
}
|
||||
|
||||
this.loadedBean = bean;
|
||||
|
||||
if (lazyLoadParentId != null) {
|
||||
if (!lazyLoadParentId.equals(this.lazyLoadParentId)) {
|
||||
// get the appropriate parent bean from the persistence context
|
||||
this.lazyLoadParentBean = (EntityBean)getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
|
||||
this.lazyLoadParentId = lazyLoadParentId;
|
||||
}
|
||||
|
||||
// add the loadedBean to the appropriate collection of lazyLoadParentBean
|
||||
lazyLoadManyProperty.addBeanToCollectionWithCreate(lazyLoadParentBean, loadedBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoadedManyBean(EntityBean manyValue) {
|
||||
this.loadedManyBean = manyValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last read bean.
|
||||
*/
|
||||
public EntityBean getLoadedBean() {
|
||||
if (manyIncluded) {
|
||||
if (prevDetailCollection instanceof BeanCollection<?>) {
|
||||
((BeanCollection<?>) prevDetailCollection).setModifyListening(manyProperty.getModifyListenMode());
|
||||
|
||||
} else if (currentDetailCollection instanceof BeanCollection<?>) {
|
||||
((BeanCollection<?>) currentDetailCollection).setModifyListening(manyProperty.getModifyListenMode());
|
||||
}
|
||||
}
|
||||
|
||||
if (prevLoadedBean != null) {
|
||||
return prevLoadedBean;
|
||||
} else {
|
||||
return loadedBean;
|
||||
// add the loadedBean to the appropriate collection of lazyLoadParentBean
|
||||
lazyLoadManyProperty.addBeanToCollectionWithCreate(lazyLoadParentBean, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,29 +383,78 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* the one/master and the second the many/detail.
|
||||
* </p>
|
||||
*/
|
||||
private boolean readRow() throws SQLException {
|
||||
private boolean readNextBean() throws SQLException {
|
||||
|
||||
synchronized (this) {
|
||||
if (cancelled) {
|
||||
if (!moveToNextRow()) {
|
||||
if (currentBean == null) {
|
||||
return false;
|
||||
} else {
|
||||
// the last bean
|
||||
nextBean = currentBean;
|
||||
loadedBeanCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataReader.next()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rowCount++;
|
||||
dataReader.resetColumnPosition();
|
||||
|
||||
if (rowNumberIncluded) {
|
||||
// row_number() column used for limit features
|
||||
dataReader.incrementPos(1);
|
||||
}
|
||||
|
||||
rootNode.load(this, null);
|
||||
loadedBeanCount++;
|
||||
|
||||
if (manyProperty == null) {
|
||||
// only single resultSet row required to build object so we are done
|
||||
// read a single resultSet row into single bean
|
||||
nextBean = rootNode.load(this, null, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextBean == null) {
|
||||
// very first read
|
||||
nextBean = rootNode.load(this, null, null);
|
||||
} else {
|
||||
// nextBean set to previously read currentBean
|
||||
nextBean = currentBean;
|
||||
// check the current row we have just moved to
|
||||
if (checkForDifferentBean()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
readUntilDifferentBeanStarted();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read resultSet rows until we hit the end or get a different bean.
|
||||
*/
|
||||
private void readUntilDifferentBeanStarted() throws SQLException {
|
||||
while (moveToNextRow()) {
|
||||
if (checkForDifferentBean()) return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the currentBean from the row data returning true if the bean
|
||||
* is different to the nextBean (false if we need to read more rows).
|
||||
*/
|
||||
private boolean checkForDifferentBean() throws SQLException {
|
||||
currentBean = rootNode.load(this, null, null);
|
||||
return currentBean != nextBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we can move to the next resultSet row.
|
||||
*/
|
||||
private boolean moveToNextRow() throws SQLException {
|
||||
|
||||
if (!dataReader.next()) {
|
||||
noMoreRows = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
rowCount++;
|
||||
dataReader.resetColumnPosition();
|
||||
if (rowNumberIncluded) {
|
||||
// row_number() column used for limit features
|
||||
dataReader.incrementPos(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public long getQueryExecutionTimeMicros() {
|
||||
@@ -506,96 +463,33 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
public boolean readBean() throws SQLException {
|
||||
|
||||
boolean result = readBeanInternal();
|
||||
|
||||
boolean result = hasNext();
|
||||
updateExecutionStatistics();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean readBeanInternal() throws SQLException {
|
||||
protected EntityBean next() {
|
||||
return nextBean;
|
||||
}
|
||||
|
||||
if (loadedBeanCount >= maxRowsLimit) {
|
||||
return false;
|
||||
}
|
||||
protected boolean hasNext() throws SQLException {
|
||||
|
||||
if (!manyIncluded) {
|
||||
// simple query... no details...
|
||||
return readRow();
|
||||
}
|
||||
|
||||
if (noMoreRows) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rowCount == 0) {
|
||||
if (!readRow()) {
|
||||
// no rows at all...
|
||||
synchronized (this) {
|
||||
if (noMoreRows || cancelled || loadedBeanCount >= maxRowsLimit) {
|
||||
return false;
|
||||
} else {
|
||||
createNewDetailCollection();
|
||||
}
|
||||
}
|
||||
|
||||
if (readIntoCurrentDetailCollection()) {
|
||||
createNewDetailCollection();
|
||||
// return prevLoadedBean
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// return loadedBean
|
||||
prevDetailCollection = null;
|
||||
prevLoadedBean = null;
|
||||
noMoreRows = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readIntoCurrentDetailCollection() throws SQLException {
|
||||
while (readRow()) {
|
||||
if (loadedBeanChanged) {
|
||||
loadedBeanChanged = false;
|
||||
return true;
|
||||
} else {
|
||||
addToCurrentDetailCollection();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createNewDetailCollection() {
|
||||
prevDetailCollection = currentDetailCollection;
|
||||
if (queryMode.equals(Mode.LAZYLOAD_MANY)) {
|
||||
// just populate the current collection
|
||||
currentDetailCollection = manyPropertyEl.elGetValue(loadedBean);
|
||||
} else {
|
||||
// create a new collection to populate and assign to the bean
|
||||
currentDetailCollection = manyProperty.createEmpty(loadedBean);
|
||||
manyPropertyEl.elSetValue(loadedBean, currentDetailCollection, false);
|
||||
}
|
||||
|
||||
if (filterMany != null) {
|
||||
// remember the for use with a refresh
|
||||
((BeanCollection<?>) currentDetailCollection).setFilterMany(filterMany);
|
||||
}
|
||||
|
||||
// the manyKey is always null for this case, just using default mapKey on the property
|
||||
currentDetailAdd = manyProperty.getBeanCollectionAdd(currentDetailCollection, null);
|
||||
addToCurrentDetailCollection();
|
||||
}
|
||||
|
||||
private void addToCurrentDetailCollection() {
|
||||
if (loadedManyBean != null) {
|
||||
currentDetailAdd.addBean(loadedManyBean);
|
||||
return readNextBean();
|
||||
}
|
||||
}
|
||||
|
||||
public BeanCollection<T> readCollection() throws SQLException {
|
||||
|
||||
readTheRows();
|
||||
while (hasNext()) {
|
||||
EntityBean bean = next();
|
||||
help.add(collection, bean);
|
||||
}
|
||||
|
||||
updateExecutionStatistics();
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
@@ -605,13 +499,12 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
executionTimeMicros = TimeUnit.NANOSECONDS.toMicros(exeNano);
|
||||
|
||||
if (autoFetchProfiling) {
|
||||
autoFetchManager
|
||||
.collectQueryInfo(objectGraphNode, loadedBeanCount, executionTimeMicros);
|
||||
autoFetchManager.collectQueryInfo(objectGraphNode, loadedBeanCount, executionTimeMicros);
|
||||
}
|
||||
queryPlan.executionTime(loadedBeanCount, executionTimeMicros, objectGraphNode);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(null, e);
|
||||
logger.error("Error updating execution statistics", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,26 +518,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
}
|
||||
}
|
||||
|
||||
private void readTheRows() throws SQLException {
|
||||
while (hasNextBean()) {
|
||||
// add to the list/set/map
|
||||
help.add(collection, getLoadedBean());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean hasNextBean() throws SQLException {
|
||||
|
||||
if (!readBeanInternal()) {
|
||||
return false;
|
||||
|
||||
} else {
|
||||
loadedBeanCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getLoadedRowDetail() {
|
||||
if (!manyIncluded) {
|
||||
if (manyProperty == null) {
|
||||
return String.valueOf(rowCount);
|
||||
} else {
|
||||
return loadedBeanCount + ":" + rowCount;
|
||||
@@ -738,13 +613,11 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* Create a PersistenceException including interesting information like the
|
||||
* bindLog and sql used.
|
||||
*/
|
||||
public static PersistenceException createPersistenceException(SQLException e, SpiTransaction t,
|
||||
String bindLog, String sql) {
|
||||
public static PersistenceException createPersistenceException(SQLException e, SpiTransaction t, String bindLog, String sql) {
|
||||
|
||||
if (t.isLogSummary()) {
|
||||
// log the error to the transaction log
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[] { "\r", "\n" },
|
||||
"\\n ");
|
||||
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, "\\n ");
|
||||
String msg = "ERROR executing query: bindLog[" + bindLog + "] error[" + errMsg + "]";
|
||||
t.logSummary(msg);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ public class CQueryEngine {
|
||||
CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request);
|
||||
try {
|
||||
|
||||
|
||||
BeanIdList list = rcQuery.findIds();
|
||||
|
||||
if (request.isLogSql()) {
|
||||
@@ -83,13 +82,13 @@ public class CQueryEngine {
|
||||
|
||||
CQueryRowCount rcQuery = queryBuilder.buildRowCountQuery(request);
|
||||
try {
|
||||
|
||||
|
||||
int rowCount = rcQuery.findRowCount();
|
||||
|
||||
if (request.isLogSql()) {
|
||||
String logSql = rcQuery.getGeneratedSql();
|
||||
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
|
||||
logSql= Str.add(logSql, "; --bind(", rcQuery.getBindLog(), ")");
|
||||
logSql = Str.add(logSql, "; --bind(", rcQuery.getBindLog(), ")");
|
||||
}
|
||||
request.logSql(logSql);
|
||||
}
|
||||
@@ -168,7 +167,7 @@ public class CQueryEngine {
|
||||
logger.trace("Future fetch already cancelled");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (request.isLogSql()) {
|
||||
logSql(cquery);
|
||||
}
|
||||
@@ -192,7 +191,7 @@ public class CQueryEngine {
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw cquery.createPersistenceException(e);
|
||||
|
||||
|
||||
} finally {
|
||||
if (cquery != null) {
|
||||
cquery.close();
|
||||
@@ -224,7 +223,7 @@ public class CQueryEngine {
|
||||
}
|
||||
|
||||
if (cquery.readBean()) {
|
||||
bean = cquery.getLoadedBean();
|
||||
bean = cquery.next();
|
||||
}
|
||||
|
||||
if (request.isLogSummary()) {
|
||||
@@ -233,7 +232,7 @@ public class CQueryEngine {
|
||||
|
||||
request.executeSecondaryQueries();
|
||||
|
||||
return (T)bean;
|
||||
return (T) bean;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw cquery.createPersistenceException(e);
|
||||
@@ -250,7 +249,7 @@ public class CQueryEngine {
|
||||
|
||||
String sql = query.getGeneratedSql();
|
||||
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
|
||||
sql= Str.add(sql, "; --bind(", query.getBindLog(), ")");
|
||||
sql = Str.add(sql, "; --bind(", query.getBindLog(), ")");
|
||||
}
|
||||
query.getTransaction().logSql(sql);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
@@ -21,263 +9,262 @@ import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
import com.avaje.ebeaninternal.server.type.RsetDataReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Executes the select row count query.
|
||||
*/
|
||||
public class CQueryFetchIds {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchIds.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchIds.class);
|
||||
|
||||
/**
|
||||
* The overall find request wrapper object.
|
||||
*/
|
||||
private final OrmQueryRequest<?> request;
|
||||
/**
|
||||
* The overall find request wrapper object.
|
||||
*/
|
||||
private final OrmQueryRequest<?> request;
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
private final BeanDescriptor<?> desc;
|
||||
|
||||
private final SpiQuery<?> query;
|
||||
private final SpiQuery<?> query;
|
||||
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
private final CQueryPredicates predicates;
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
private final CQueryPredicates predicates;
|
||||
|
||||
/**
|
||||
* The final sql that is generated.
|
||||
*/
|
||||
private final String sql;
|
||||
/**
|
||||
* The final sql that is generated.
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
private RsetDataReader dataReader;
|
||||
|
||||
/**
|
||||
* The statement used to create the resultSet.
|
||||
*/
|
||||
private PreparedStatement pstmt;
|
||||
private RsetDataReader dataReader;
|
||||
|
||||
private String bindLog;
|
||||
/**
|
||||
* The statement used to create the resultSet.
|
||||
*/
|
||||
private PreparedStatement pstmt;
|
||||
|
||||
private long startNano;
|
||||
|
||||
private int executionTimeMicros;
|
||||
private String bindLog;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private final int maxRows;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchIds(OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
private int executionTimeMicros;
|
||||
|
||||
this.request = request;
|
||||
this.query = request.getQuery();
|
||||
this.sql = sql;
|
||||
this.maxRows = query.getMaxRows();
|
||||
private int rowCount;
|
||||
|
||||
query.setGeneratedSql(sql);
|
||||
private final int maxRows;
|
||||
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchIds(OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this query.
|
||||
*/
|
||||
public String getSummary() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("FindIds exeMicros[").append(executionTimeMicros)
|
||||
.append("] rows[").append(rowCount)
|
||||
.append("] type[").append(desc.getName())
|
||||
.append("] predicates[").append(predicates.getLogWhereSql())
|
||||
.append("] bind[").append(bindLog).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
this.request = request;
|
||||
this.query = request.getQuery();
|
||||
this.sql = sql;
|
||||
this.maxRows = query.getMaxRows();
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
public String getBindLog() {
|
||||
return bindLog;
|
||||
query.setGeneratedSql(sql);
|
||||
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this query.
|
||||
*/
|
||||
public String getSummary() {
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("FindIds exeMicros[").append(executionTimeMicros)
|
||||
.append("] rows[").append(rowCount)
|
||||
.append("] type[").append(desc.getName())
|
||||
.append("] predicates[").append(predicates.getLogWhereSql())
|
||||
.append("] bind[").append(bindLog).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
public String getBindLog() {
|
||||
return bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql.
|
||||
*/
|
||||
public String getGeneratedSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query returning the row count.
|
||||
*/
|
||||
public BeanIdList findIds() throws SQLException {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
|
||||
try {
|
||||
// get the list that we are going to put the id's into.
|
||||
// This was already set so that it is available to be
|
||||
// read by other threads (it is a synchronised list)
|
||||
List<Object> idList = query.getIdList();
|
||||
if (idList == null) {
|
||||
// running in foreground thread (not FutureIds query)
|
||||
idList = Collections.synchronizedList(new ArrayList<Object>());
|
||||
query.setIdList(idList);
|
||||
}
|
||||
|
||||
BeanIdList result = new BeanIdList(idList);
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
if (query.getBufferFetchSizeHint() > 0) {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
if (query.getTimeout() > 0) {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(new DataBind(pstmt));
|
||||
|
||||
ResultSet rset = pstmt.executeQuery();
|
||||
dataReader = new RsetDataReader(rset);
|
||||
|
||||
boolean hitMaxRows = false;
|
||||
boolean hasMoreRows = false;
|
||||
rowCount = 0;
|
||||
|
||||
DbReadContext ctx = new DbContext();
|
||||
|
||||
while (rset.next()) {
|
||||
Object idValue = desc.getIdBinder().read(ctx);
|
||||
idList.add(idValue);
|
||||
// reset back to 0
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
|
||||
if (maxRows > 0 && rowCount == maxRows) {
|
||||
hitMaxRows = true;
|
||||
hasMoreRows = rset.next();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (hitMaxRows) {
|
||||
result.setHasMore(hasMoreRows);
|
||||
}
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int) exeNano / 1000;
|
||||
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
* <p>
|
||||
* The jdbc resultSet and statement need to be closed. Its important that
|
||||
* this method is called.
|
||||
* </p>
|
||||
*/
|
||||
private void close() {
|
||||
try {
|
||||
if (dataReader != null) {
|
||||
dataReader.close();
|
||||
dataReader = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
try {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
pstmt = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DbContext implements DbReadContext {
|
||||
|
||||
public void propagateState(Object e) {
|
||||
throw new RuntimeException("Not Called");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql.
|
||||
*/
|
||||
public String getGeneratedSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public SpiOrmQueryRequest<?> getQueryRequest() {
|
||||
return request;
|
||||
}
|
||||
public Mode getQueryMode() {
|
||||
return Mode.NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query returning the row count.
|
||||
*/
|
||||
public BeanIdList findIds() throws SQLException {
|
||||
public DataReader getDataReader() {
|
||||
return dataReader;
|
||||
}
|
||||
|
||||
startNano = System.nanoTime();
|
||||
|
||||
try {
|
||||
// get the list that we are going to put the id's into.
|
||||
// This was already set so that it is available to be
|
||||
// read by other threads (it is a synchronised list)
|
||||
List<Object> idList = query.getIdList();
|
||||
if (idList == null){
|
||||
// running in foreground thread (not FutureIds query)
|
||||
idList = Collections.synchronizedList(new ArrayList<Object>());
|
||||
query.setIdList(idList);
|
||||
}
|
||||
|
||||
BeanIdList result = new BeanIdList(idList);
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
if (query.getBufferFetchSizeHint() > 0){
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
if (query.getTimeout() > 0){
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(new DataBind(pstmt));
|
||||
|
||||
ResultSet rset = pstmt.executeQuery();
|
||||
dataReader = new RsetDataReader(rset);
|
||||
|
||||
boolean hitMaxRows = false;
|
||||
boolean hasMoreRows = false;
|
||||
rowCount = 0;
|
||||
|
||||
DbReadContext ctx = new DbContext();
|
||||
|
||||
while (rset.next()){
|
||||
Object idValue = desc.getIdBinder().read(ctx);
|
||||
idList.add(idValue);
|
||||
// reset back to 0
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
|
||||
if (maxRows > 0 && rowCount == maxRows) {
|
||||
hitMaxRows = true;
|
||||
hasMoreRows = rset.next();
|
||||
break;
|
||||
public Boolean isReadOnly() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (hitMaxRows){
|
||||
result.setHasMore(hasMoreRows);
|
||||
}
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int)exeNano/1000;
|
||||
public boolean isRawSql() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
public void register(String path, EntityBeanIntercept ebi) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
* <p>
|
||||
* The jdbc resultSet and statement need to be closed. Its important that
|
||||
* this method is called.
|
||||
* </p>
|
||||
*/
|
||||
private void close() {
|
||||
try {
|
||||
if (dataReader != null) {
|
||||
dataReader.close();
|
||||
dataReader = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
try {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
pstmt = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
}
|
||||
public void register(String path, BeanCollection<?> bc) {
|
||||
}
|
||||
|
||||
|
||||
class DbContext implements DbReadContext {
|
||||
public BeanPropertyAssocMany<?> getManyProperty() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public void propagateState(Object e) {
|
||||
throw new RuntimeException("Not Called");
|
||||
}
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public Mode getQueryMode() {
|
||||
return Mode.NORMAL;
|
||||
}
|
||||
|
||||
public DataReader getDataReader() {
|
||||
return dataReader;
|
||||
}
|
||||
public boolean isAutoFetchProfiling() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Boolean isReadOnly() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
public boolean isRawSql() {
|
||||
return false;
|
||||
}
|
||||
public void profileBean(EntityBeanIntercept ebi, String prefix) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void register(String path, EntityBeanIntercept ebi){
|
||||
}
|
||||
public void setCurrentPrefix(String currentPrefix, Map<String, String> pathMap) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void register(String path, BeanCollection<?> bc){
|
||||
}
|
||||
public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?> getManyProperty() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isAutoFetchProfiling() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void profileBean(EntityBeanIntercept ebi, String prefix) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setCurrentPrefix(String currentPrefix,Map<String, String> pathMap) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setLoadedBean(EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setLoadedManyBean(EntityBean loadedBean) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
class CQueryIteratorSimple<T> implements QueryIterator<T> {
|
||||
|
||||
private final CQuery<T> cquery;
|
||||
|
||||
private final OrmQueryRequest<T> request;
|
||||
|
||||
CQueryIteratorSimple(CQuery<T> cquery, OrmQueryRequest<T> request) {
|
||||
@@ -23,7 +24,7 @@ class CQueryIteratorSimple<T> implements QueryIterator<T> {
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
request.flushPersistenceContextOnIterate();
|
||||
return cquery.hasNextBean();
|
||||
return cquery.hasNext();
|
||||
} catch (SQLException e) {
|
||||
throw cquery.createPersistenceException(e);
|
||||
}
|
||||
@@ -31,7 +32,7 @@ class CQueryIteratorSimple<T> implements QueryIterator<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T next() {
|
||||
return (T)cquery.getLoadedBean();
|
||||
return (T) cquery.next();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
@@ -36,8 +36,8 @@ class CQueryIteratorWithBuffer<T> implements QueryIterator<T> {
|
||||
|
||||
int i = -1;
|
||||
while (moreToLoad && ++i < bufferSize) {
|
||||
if (cquery.hasNextBean()) {
|
||||
buffer.add((T)cquery.getLoadedBean());
|
||||
if (cquery.hasNext()) {
|
||||
buffer.add((T) cquery.next());
|
||||
} else {
|
||||
moreToLoad = false;
|
||||
}
|
||||
|
||||
@@ -9,31 +9,25 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
public interface SqlTreeNode {
|
||||
|
||||
public static final String PERIOD = ".";
|
||||
String COMMA = ", ";
|
||||
|
||||
public static final String COMMA = ", ";
|
||||
|
||||
public static final int NORMAL = 0;
|
||||
public static final int SHARED = 1;
|
||||
public static final int READONLY = 2;
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain);
|
||||
void buildSelectExpressionChain(List<String> selectChain);
|
||||
|
||||
/**
|
||||
* Append the required column information to the SELECT part of the sql
|
||||
* statement.
|
||||
*/
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
|
||||
/**
|
||||
* Append to the FROM part of the sql.
|
||||
*/
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType);
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType);
|
||||
|
||||
/**
|
||||
* Append any where predicates for inheritance.
|
||||
*/
|
||||
public void appendWhere(DbSqlContext ctx);
|
||||
void appendWhere(DbSqlContext ctx);
|
||||
|
||||
/**
|
||||
* Load the appropriate information from the SqlSelectReader.
|
||||
@@ -41,8 +35,7 @@ public interface SqlTreeNode {
|
||||
* At a high level this actually controls the reading of the data from the
|
||||
* jdbc resultSet and putting it into the bean etc.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException;
|
||||
EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -69,7 +69,9 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
protected final Map<String, String> pathMap;
|
||||
|
||||
protected final BeanPropertyAssocMany<?> lazyLoadParent;
|
||||
|
||||
|
||||
private final IdBinder lazyLoadParentIdBinder;
|
||||
|
||||
public SqlTreeNodeBean(String prefix, BeanPropertyAssoc<?> beanProp, SqlTreeProperties props,
|
||||
List<SqlTreeNode> myChildren, boolean withId) {
|
||||
|
||||
@@ -83,6 +85,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
SqlTreeProperties props, List<SqlTreeNode> myChildren, boolean withId, BeanPropertyAssocMany<?> lazyLoadParent) {
|
||||
|
||||
this.lazyLoadParent = lazyLoadParent;
|
||||
this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.getBeanDescriptor().getIdBinder();
|
||||
this.prefix = prefix;
|
||||
this.nodeBeanProp = beanProp;
|
||||
this.desc = desc;
|
||||
@@ -134,9 +137,6 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
protected void postLoad(DbReadContext cquery, EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
if (readId) {
|
||||
idBinder.buildSelectExpressionChain(prefix, selectChain);
|
||||
@@ -155,11 +155,11 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
/**
|
||||
* read the properties from the resultSet.
|
||||
*/
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException {
|
||||
public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException {
|
||||
|
||||
Object lazyLoadParentId = null;
|
||||
if (lazyLoadParent != null) {
|
||||
lazyLoadParentId = lazyLoadParent.getBeanDescriptor().getIdBinder().read(ctx);
|
||||
if (lazyLoadParentIdBinder != null) {
|
||||
lazyLoadParentId = lazyLoadParentIdBinder.read(ctx);
|
||||
}
|
||||
|
||||
// bean already existing in the persistence context
|
||||
@@ -196,12 +196,8 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
PersistenceContext persistenceContext = !readId ? null : ctx.getPersistenceContext();
|
||||
|
||||
Object id = null;
|
||||
if (!readId) {
|
||||
// report type bean... or perhaps excluding the id for SqlSelect?
|
||||
|
||||
} else {
|
||||
id = localIdBinder.readSet(ctx, localBean);
|
||||
if (readId) {
|
||||
Object id = localIdBinder.readSet(ctx, localBean);
|
||||
if (id == null) {
|
||||
// bean must be null...
|
||||
localBean = null;
|
||||
@@ -265,51 +261,45 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
// read each child... and let them set their
|
||||
// values back to this localBean
|
||||
children[i].load(ctx, localBean);
|
||||
children[i].load(ctx, localBean, contextBean);
|
||||
}
|
||||
|
||||
if (lazyLoadMany) {
|
||||
// special case where we load children
|
||||
|
||||
} else if (localBean != null) {
|
||||
|
||||
if (!lazyLoadMany && localBean != null) {
|
||||
ctx.setCurrentPrefix(prefix, pathMap);
|
||||
if (readId) {
|
||||
createListProxies(localDesc, ctx, localBean);
|
||||
}
|
||||
localDesc.postLoad(localBean, null);
|
||||
|
||||
if (localBean instanceof EntityBean) {
|
||||
EntityBeanIntercept ebi = ((EntityBean) localBean)._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(persistenceContext);
|
||||
if (Mode.LAZYLOAD_BEAN.equals(queryMode)) {
|
||||
// Lazy Load does not reset the dirty state
|
||||
ebi.setLoadedLazy();
|
||||
} else {
|
||||
// normal bean loading
|
||||
ebi.setLoaded();
|
||||
}
|
||||
|
||||
if (partialObject) {
|
||||
if (readId) {
|
||||
// register for lazy loading
|
||||
ctx.register(null, ebi);
|
||||
}
|
||||
} else {
|
||||
ebi.setFullyLoadedBean(true);
|
||||
}
|
||||
|
||||
if (disableLazyLoad) {
|
||||
// bean does not have an Id or is SqlSelect based
|
||||
ebi.setDisableLazyLoad(true);
|
||||
}
|
||||
if (ctx.isAutoFetchProfiling()) {
|
||||
// collect autofetch profiling for this bean...
|
||||
ctx.profileBean(ebi, prefix);
|
||||
}
|
||||
EntityBeanIntercept ebi = localBean._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(persistenceContext);
|
||||
if (Mode.LAZYLOAD_BEAN.equals(queryMode)) {
|
||||
// Lazy Load does not reset the dirty state
|
||||
ebi.setLoadedLazy();
|
||||
} else {
|
||||
// normal bean loading
|
||||
ebi.setLoaded();
|
||||
}
|
||||
|
||||
if (partialObject) {
|
||||
if (readId) {
|
||||
// register for lazy loading
|
||||
ctx.register(null, ebi);
|
||||
}
|
||||
} else {
|
||||
ebi.setFullyLoadedBean(true);
|
||||
}
|
||||
|
||||
if (disableLazyLoad) {
|
||||
// bean does not have an Id or is SqlSelect based
|
||||
ebi.setDisableLazyLoad(true);
|
||||
}
|
||||
if (ctx.isAutoFetchProfiling()) {
|
||||
// collect autofetch profiling for this bean...
|
||||
ctx.profileBean(ebi, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentBean != null) {
|
||||
// set this back to the parentBean
|
||||
nodeBeanProp.setValue(parentBean, contextBean);
|
||||
@@ -317,13 +307,13 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
if (!readId) {
|
||||
// a bean with no Id (never found in context)
|
||||
postLoad(ctx, localBean, id, null);
|
||||
return localBean;
|
||||
|
||||
} else {
|
||||
// return the contextBean which is either the localBean
|
||||
// read from the resultSet and put into the context OR
|
||||
// the 'matching' bean that already existed in the context
|
||||
postLoad(ctx, contextBean, id, lazyLoadParentId);
|
||||
if (lazyLoadParentId != null) {
|
||||
ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId);
|
||||
}
|
||||
return contextBean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,10 +329,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
BeanPropertyAssocMany<?>[] manys = localDesc.propertiesMany();
|
||||
for (int i = 0; i < manys.length; i++) {
|
||||
|
||||
if (fetchedMany != null && fetchedMany.equals(manys[i])) {
|
||||
// this many property is included in the query...
|
||||
// it is being loaded with real row data (result[1])
|
||||
} else {
|
||||
if (fetchedMany == null || !fetchedMany.equals(manys[i])) {
|
||||
// create a proxy for the many (deferred fetching)
|
||||
BeanCollection<?> ref = manys[i].createReferenceIfNull(localBean);
|
||||
if (ref != null && !ref.isRegisteredWithLoadContext()) {
|
||||
@@ -418,13 +405,9 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
|
||||
// Only apply inheritance to root node as any join will alreay have the inheritance join include - see TableJoin
|
||||
if (inheritInfo != null && nodeBeanProp == null) {
|
||||
if (inheritInfo.isRoot()) {
|
||||
// at root of hierarchy so don't bother
|
||||
// adding a where clause because we want
|
||||
// all the types...
|
||||
} else {
|
||||
// Only apply inheritance to root node as any join will alreay have the inheritance join include - see TableJoin
|
||||
if (inheritInfo != null && nodeBeanProp == null) {
|
||||
if (!inheritInfo.isRoot()) {
|
||||
// restrict to this type and
|
||||
// sub types of this type.
|
||||
if (ctx.length() > 0) {
|
||||
|
||||
@@ -21,81 +21,76 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
*/
|
||||
public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
|
||||
|
||||
private final BeanPropertyAssoc<?> assocBeanProperty;
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final boolean manyJoin;
|
||||
|
||||
private List<SqlTreeNodeExtraJoin> children;
|
||||
|
||||
public SqlTreeNodeExtraJoin(String prefix, BeanPropertyAssoc<?> assocBeanProperty) {
|
||||
this.prefix = prefix;
|
||||
this.assocBeanProperty = assocBeanProperty;
|
||||
this.manyJoin = assocBeanProperty instanceof BeanPropertyAssocMany<?>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
private final BeanPropertyAssoc<?> assocBeanProperty;
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final boolean manyJoin;
|
||||
|
||||
private List<SqlTreeNodeExtraJoin> children;
|
||||
|
||||
public SqlTreeNodeExtraJoin(String prefix, BeanPropertyAssoc<?> assocBeanProperty) {
|
||||
this.prefix = prefix;
|
||||
this.assocBeanProperty = assocBeanProperty;
|
||||
this.manyJoin = assocBeanProperty instanceof BeanPropertyAssocMany<?>;
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the extra join is a many join.
|
||||
* <p>
|
||||
* This means we need to add distinct to the sql query.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isManyJoin() {
|
||||
return manyJoin;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the extra join is a many join.
|
||||
* <p>
|
||||
* This means we need to add distinct to the sql query.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isManyJoin() {
|
||||
return manyJoin;
|
||||
}
|
||||
public void addChild(SqlTreeNodeExtraJoin child) {
|
||||
if (children == null) {
|
||||
children = new ArrayList<SqlTreeNodeExtraJoin>();
|
||||
}
|
||||
children.add(child);
|
||||
}
|
||||
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
public String getName() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void addChild(SqlTreeNodeExtraJoin child){
|
||||
if (children == null){
|
||||
children = new ArrayList<SqlTreeNodeExtraJoin>();
|
||||
}
|
||||
children.add(child);
|
||||
}
|
||||
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
boolean manyToMany = false;
|
||||
|
||||
if (assocBeanProperty instanceof BeanPropertyAssocMany<?>){
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>)assocBeanProperty;
|
||||
if (manyProp.isManyToMany()){
|
||||
|
||||
manyToMany = true;
|
||||
|
||||
String alias = ctx.getTableAlias(prefix);
|
||||
String[] split = SplitName.split(prefix);
|
||||
String parentAlias = ctx.getTableAlias(split[0]);
|
||||
String alias2 = alias+"z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
|
||||
assocBeanProperty.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!manyToMany){
|
||||
assocBeanProperty.addJoin(joinType, prefix, ctx);
|
||||
}
|
||||
boolean manyToMany = false;
|
||||
|
||||
if (assocBeanProperty instanceof BeanPropertyAssocMany<?>) {
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) assocBeanProperty;
|
||||
if (manyProp.isManyToMany()) {
|
||||
|
||||
manyToMany = true;
|
||||
|
||||
String alias = ctx.getTableAlias(prefix);
|
||||
String[] split = SplitName.split(prefix);
|
||||
String parentAlias = ctx.getTableAlias(split[0]);
|
||||
String alias2 = alias + "z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
|
||||
assocBeanProperty.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!manyToMany) {
|
||||
assocBeanProperty.addJoin(joinType, prefix, ctx);
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
|
||||
if (manyJoin) {
|
||||
// if AUTO then make all decendants use OUTER JOIN
|
||||
// if AUTO then make all descendants use OUTER JOIN
|
||||
joinType = joinType.autoToOuter();
|
||||
}
|
||||
|
||||
@@ -106,22 +101,23 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
}
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
}
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException {
|
||||
}
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,24 +10,22 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
|
||||
|
||||
final BeanPropertyAssocMany<?> manyProp;
|
||||
|
||||
public SqlTreeNodeManyRoot(String prefix, BeanPropertyAssocMany<?> prop, SqlTreeProperties props, List<SqlTreeNode> myList) {
|
||||
super(prefix, prop, prop.getTargetDescriptor(), props, myList, true, null);
|
||||
this.manyProp = prop;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postLoad(DbReadContext cquery, EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
|
||||
// put the localBean into the manyValue so that it
|
||||
// is added to the collection/map
|
||||
cquery.setLoadedManyBean(loadedBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DbReadContext cquery, EntityBean parentBean) throws SQLException {
|
||||
public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException {
|
||||
// pass in null for parentBean because the localBean
|
||||
// that is built is added to a collection rather than
|
||||
// being set to the parentBean directly
|
||||
super.load(cquery, null);
|
||||
EntityBean detailBean = super.load(cquery, null, null);
|
||||
// initialise the collection and add detailBean if it is not null
|
||||
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean);
|
||||
return detailBean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,91 +17,80 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
*/
|
||||
public class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
|
||||
|
||||
private final String parentPrefix;
|
||||
|
||||
private final String prefix;
|
||||
private final String parentPrefix;
|
||||
|
||||
private final BeanPropertyAssoc<?> nodeBeanProp;
|
||||
|
||||
/**
|
||||
* Child joins.
|
||||
*/
|
||||
private final SqlTreeNode[] children;
|
||||
|
||||
/**
|
||||
* The many where join which is either INNER or OUTER.
|
||||
*/
|
||||
private final SqlJoinType manyJoinType;
|
||||
private final String prefix;
|
||||
|
||||
public SqlTreeNodeManyWhereJoin(String prefix, BeanPropertyAssoc<?> prop, SqlJoinType manyJoinType) {
|
||||
|
||||
this.nodeBeanProp = prop;
|
||||
this.prefix = prefix;
|
||||
this.manyJoinType = manyJoinType;
|
||||
private final BeanPropertyAssoc<?> nodeBeanProp;
|
||||
|
||||
String[] split = SplitName.split(prefix);
|
||||
this.parentPrefix = split[0];
|
||||
|
||||
List<SqlTreeNode> childrenList = new ArrayList<SqlTreeNode>(0);
|
||||
this.children = childrenList.toArray(new SqlTreeNode[childrenList.size()]);
|
||||
/**
|
||||
* The many where join which is either INNER or OUTER.
|
||||
*/
|
||||
private final SqlJoinType manyJoinType;
|
||||
|
||||
public SqlTreeNodeManyWhereJoin(String prefix, BeanPropertyAssoc<?> prop, SqlJoinType manyJoinType) {
|
||||
|
||||
this.nodeBeanProp = prop;
|
||||
this.prefix = prefix;
|
||||
this.manyJoinType = manyJoinType;
|
||||
|
||||
String[] split = SplitName.split(prefix);
|
||||
this.parentPrefix = split[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to the FROM clause for this node.
|
||||
*/
|
||||
@Override
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType currentJoinType) {
|
||||
|
||||
// always use the join type as per this many where join
|
||||
// (OUTER for disjunction and otherwise INNER)
|
||||
appendFromBaseTable(ctx, manyJoinType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join to base table for this node. This includes a join to the
|
||||
* intersection table if this is a ManyToMany node.
|
||||
*/
|
||||
public void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
String alias = ctx.getTableAliasManyWhere(prefix);
|
||||
String parentAlias = ctx.getTableAliasManyWhere(parentPrefix);
|
||||
|
||||
if (nodeBeanProp instanceof BeanPropertyAssocOne<?>) {
|
||||
nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) nodeBeanProp;
|
||||
if (!manyProp.isManyToMany()) {
|
||||
manyProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
String alias2 = alias + "z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
manyProp.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to the FROM clause for this node.
|
||||
*/
|
||||
@Override
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType currentJoinType) {
|
||||
|
||||
// always use the join type as per this many where join
|
||||
// (OUTER for disjunction and otherwise INNER)
|
||||
appendFromBaseTable(ctx, manyJoinType);
|
||||
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
children[i].appendFrom(ctx, manyJoinType);
|
||||
}
|
||||
}
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
/**
|
||||
* Join to base table for this node. This includes a join to the
|
||||
* intersection table if this is a ManyToMany node.
|
||||
*/
|
||||
public void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
String alias = ctx.getTableAliasManyWhere(prefix);
|
||||
String parentAlias = ctx.getTableAliasManyWhere(parentPrefix);
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
if (nodeBeanProp instanceof BeanPropertyAssocOne<?>){
|
||||
nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>)nodeBeanProp;
|
||||
if (!manyProp.isManyToMany()) {
|
||||
manyProp.addJoin(joinType, parentAlias, alias, ctx);
|
||||
|
||||
} else {
|
||||
String alias2 = alias + "z_";
|
||||
|
||||
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
|
||||
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
|
||||
manyProp.addJoin(joinType, alias2, alias, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
public void load(DbReadContext ctx, EntityBean parentBean) throws SQLException {
|
||||
// nothing to do here
|
||||
}
|
||||
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException {
|
||||
// nothing to do here
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,41 +1,32 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the root node of the Sql Tree.
|
||||
*/
|
||||
public final class SqlTreeNodeRoot extends SqlTreeNodeBean {
|
||||
|
||||
private final TableJoin includeJoin;
|
||||
|
||||
/**
|
||||
* Specify for SqlSelect to include an Id property or not.
|
||||
*/
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId, TableJoin includeJoin, BeanPropertyAssocMany<?> many){
|
||||
super(null, null, desc, props, myList, withId, many);
|
||||
this.includeJoin = includeJoin;
|
||||
}
|
||||
private final TableJoin includeJoin;
|
||||
|
||||
/**
|
||||
* Specify for SqlSelect to include an Id property or not.
|
||||
*/
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId, TableJoin includeJoin, BeanPropertyAssocMany<?> many) {
|
||||
super(null, null, desc, props, myList, withId, many);
|
||||
this.includeJoin = includeJoin;
|
||||
}
|
||||
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId) {
|
||||
super(null, null, desc, props, myList, withId, null);
|
||||
this.includeJoin = null;
|
||||
}
|
||||
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId) {
|
||||
super(null, null, desc, props, myList, withId, null);
|
||||
this.includeJoin = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postLoad(DbReadContext cquery, EntityBean loadedBean, Object id, Object lazyLoadParentId) {
|
||||
|
||||
// set the current bean with id...
|
||||
cquery.setLoadedBean(loadedBean, id, lazyLoadParentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the root node there is no join type or on clause etc.
|
||||
*/
|
||||
@@ -53,5 +44,5 @@ public final class SqlTreeNodeRoot extends SqlTreeNodeBean {
|
||||
|
||||
return joinType;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -14,86 +14,69 @@ public class SqlTreeProperties {
|
||||
|
||||
private static final TableJoin[] EMPTY_TABLE_JOINS = new TableJoin[0];
|
||||
|
||||
/**
|
||||
* True if this node of the tree should have read only entity beans.
|
||||
*/
|
||||
private boolean readOnly;
|
||||
/**
|
||||
* True if this node of the tree should have read only entity beans.
|
||||
*/
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* set to false if the id field is not included.
|
||||
*/
|
||||
private boolean includeId = true;
|
||||
private TableJoin[] tableJoins = EMPTY_TABLE_JOINS;
|
||||
|
||||
private TableJoin[] tableJoins = EMPTY_TABLE_JOINS;
|
||||
/**
|
||||
* The bean properties in order.
|
||||
*/
|
||||
private List<BeanProperty> propsList = new ArrayList<BeanProperty>();
|
||||
|
||||
/**
|
||||
* The bean properties in order.
|
||||
*/
|
||||
private List<BeanProperty> propsList = new ArrayList<BeanProperty>();
|
||||
|
||||
/**
|
||||
* Maintain a list of property names to detect embedded bean additions.
|
||||
*/
|
||||
private LinkedHashSet<String> propNames = new LinkedHashSet<String>();
|
||||
/**
|
||||
* Maintain a list of property names to detect embedded bean additions.
|
||||
*/
|
||||
private LinkedHashSet<String> propNames = new LinkedHashSet<String>();
|
||||
|
||||
private boolean allProperties;
|
||||
|
||||
public SqlTreeProperties() {
|
||||
}
|
||||
|
||||
public boolean containsProperty(String propName){
|
||||
return propNames.contains(propName);
|
||||
}
|
||||
|
||||
public void add(BeanProperty[] props) {
|
||||
for (BeanProperty beanProperty : props) {
|
||||
propsList.add(beanProperty);
|
||||
}
|
||||
}
|
||||
public SqlTreeProperties() {
|
||||
}
|
||||
|
||||
public void add(BeanProperty prop) {
|
||||
public boolean containsProperty(String propName) {
|
||||
return propNames.contains(propName);
|
||||
}
|
||||
|
||||
public void add(BeanProperty[] props) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
propsList.add(props[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(BeanProperty prop) {
|
||||
propsList.add(prop);
|
||||
propNames.add(prop.getName());
|
||||
}
|
||||
|
||||
public BeanProperty[] getProps() {
|
||||
return propsList.toArray(new BeanProperty[propsList.size()]);
|
||||
}
|
||||
propNames.add(prop.getName());
|
||||
}
|
||||
|
||||
public boolean isIncludeId() {
|
||||
return includeId;
|
||||
}
|
||||
public BeanProperty[] getProps() {
|
||||
return propsList.toArray(new BeanProperty[propsList.size()]);
|
||||
}
|
||||
|
||||
public void setIncludeId(boolean includeId) {
|
||||
this.includeId = includeId;
|
||||
}
|
||||
public boolean isPartialObject() {
|
||||
return !allProperties;
|
||||
}
|
||||
|
||||
public boolean isPartialObject() {
|
||||
return !allProperties;
|
||||
}
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
public TableJoin[] getTableJoins() {
|
||||
return tableJoins;
|
||||
}
|
||||
|
||||
public TableJoin[] getTableJoins() {
|
||||
return tableJoins;
|
||||
}
|
||||
|
||||
public void setTableJoins(TableJoin[] tableJoins) {
|
||||
this.tableJoins = tableJoins;
|
||||
}
|
||||
public void setTableJoins(TableJoin[] tableJoins) {
|
||||
this.tableJoins = tableJoins;
|
||||
}
|
||||
|
||||
public void setAllProperties(boolean allProperties) {
|
||||
this.allProperties = allProperties;
|
||||
}
|
||||
|
||||
public boolean isAllProperties() {
|
||||
return allProperties;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Level1 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@ManyToMany(cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "level1_level4",
|
||||
joinColumns = @JoinColumn(name = "level1_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "level4_id", referencedColumnName = "id")
|
||||
)
|
||||
Set<Level4> level4s;
|
||||
|
||||
@ManyToMany(cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "level1_level2",
|
||||
joinColumns = @JoinColumn(name = "level1_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "level2_id", referencedColumnName = "id")
|
||||
)
|
||||
Set<Level2> level2s;
|
||||
|
||||
String name;
|
||||
|
||||
public Level1(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Set<Level2> getLevel2s() {
|
||||
return level2s;
|
||||
}
|
||||
|
||||
public Set<Level4> getLevel4s() {
|
||||
return level4s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class Level2 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
|
||||
@JoinTable(
|
||||
name = "level2_level3",
|
||||
joinColumns = @JoinColumn(name = "level2_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "level3_id", referencedColumnName = "id")
|
||||
)
|
||||
List<Level3> level3s;
|
||||
|
||||
String name;
|
||||
|
||||
public Level2(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<Level3> getLevel3s() {
|
||||
return level3s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Level3 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
public Level3(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Level4 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
public Level4(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.avaje.tests.level.test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.tests.level.Level1;
|
||||
import com.avaje.tests.level.Level2;
|
||||
import com.avaje.tests.level.Level3;
|
||||
import com.avaje.tests.level.Level4;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ManyToManyTest extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
Level4 i = new Level4("i");
|
||||
Level4 ii = new Level4("ii");
|
||||
Level4 iii = new Level4("iii");
|
||||
|
||||
Ebean.save(i);
|
||||
Ebean.save(ii);
|
||||
Ebean.save(iii);
|
||||
|
||||
Level3 a = new Level3("a");
|
||||
Level3 b = new Level3("b");
|
||||
|
||||
Ebean.save(a);
|
||||
Ebean.save(b);
|
||||
|
||||
Level2 one = new Level2("one");
|
||||
Level2 two = new Level2("two");
|
||||
|
||||
Ebean.save(one);
|
||||
Ebean.save(two);
|
||||
|
||||
Level1 x1 = new Level1("x1");
|
||||
Level1 x2 = new Level1("x2");
|
||||
Level1 x3 = new Level1("x3");
|
||||
Level1 x4 = new Level1("x4");
|
||||
Level1 x5 = new Level1("x5");
|
||||
|
||||
x1.getLevel2s().add(one);
|
||||
x2.getLevel2s().add(one);
|
||||
x3.getLevel2s().add(two);
|
||||
x4.getLevel2s().add(two);
|
||||
x5.getLevel2s().add(two);
|
||||
|
||||
x1.getLevel4s().add(i);
|
||||
x1.getLevel4s().add(ii);
|
||||
x2.getLevel4s().add(ii);
|
||||
x2.getLevel4s().add(iii);
|
||||
|
||||
Ebean.save(x1);
|
||||
Ebean.save(x2);
|
||||
Ebean.save(x3);
|
||||
Ebean.save(x4);
|
||||
Ebean.save(x5);
|
||||
|
||||
// this query had the original problem
|
||||
List<Level1> things = Ebean.find(Level1.class)
|
||||
.fetch("level4s")
|
||||
.fetch("level2s")
|
||||
.fetch("level2s.level3s")
|
||||
.order().asc("id")
|
||||
.findList();
|
||||
|
||||
validateObjectGraph(i, ii, iii, one, two, x1, x2, x3, x4, x5, things);
|
||||
|
||||
|
||||
things = Ebean.find(Level1.class)
|
||||
.fetch("level2s")
|
||||
.fetch("level2s.level3s")
|
||||
.fetch("level4s")
|
||||
.order().asc("id")
|
||||
.findList();
|
||||
|
||||
validateObjectGraph(i, ii, iii, one, two, x1, x2, x3, x4, x5, things);
|
||||
|
||||
|
||||
things = Ebean.find(Level1.class)
|
||||
.fetch("level2s")
|
||||
.fetch("level4s")
|
||||
.order().asc("id")
|
||||
.findList();
|
||||
|
||||
validateObjectGraph(i, ii, iii, one, two, x1, x2, x3, x4, x5, things);
|
||||
|
||||
} finally {
|
||||
Ebean.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateObjectGraph(Level4 i, Level4 ii, Level4 iii, Level2 one, Level2 two, Level1 x1, Level1 x2, Level1 x3, Level1 x4, Level1 x5, List<Level1> things) {
|
||||
|
||||
assertEquals(5, things.size());
|
||||
|
||||
// x1's are in order expected
|
||||
assertEquals(x1.getId(), things.get(0).getId());
|
||||
assertEquals(x2.getId(), things.get(1).getId());
|
||||
assertEquals(x3.getId(), things.get(2).getId());
|
||||
assertEquals(x4.getId(), things.get(3).getId());
|
||||
assertEquals(x5.getId(), things.get(4).getId());
|
||||
|
||||
// x1 to level4s
|
||||
assertEquals(2, things.get(0).getLevel4s().size());
|
||||
assertTrue(contains(things.get(0).getLevel4s(), i));
|
||||
assertTrue(contains(things.get(0).getLevel4s(), ii));
|
||||
|
||||
// x2 to level4s
|
||||
assertEquals(2, things.get(1).getLevel4s().size());
|
||||
assertTrue(contains(things.get(1).getLevel4s(), ii));
|
||||
assertTrue(contains(things.get(1).getLevel4s(), iii));
|
||||
|
||||
// x3 etc to level4s
|
||||
assertEquals(0, things.get(2).getLevel4s().size());
|
||||
assertEquals(0, things.get(3).getLevel4s().size());
|
||||
assertEquals(0, things.get(4).getLevel4s().size());
|
||||
|
||||
// level2 relationships
|
||||
for (final Level1 curThing : things) {
|
||||
assertEquals(1, curThing.getLevel2s().size());
|
||||
}
|
||||
assertTrue(contains(things.get(0).getLevel2s(), one));
|
||||
assertTrue(contains(things.get(1).getLevel2s(), one));
|
||||
assertTrue(contains(things.get(2).getLevel2s(), two));
|
||||
assertTrue(contains(things.get(3).getLevel2s(), two));
|
||||
assertTrue(contains(things.get(4).getLevel2s(), two));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if match exists in level4s.
|
||||
*/
|
||||
private boolean contains(Set<Level4> level4s, Level4 match) {
|
||||
for (Level4 level4 : level4s) {
|
||||
if (level4.getId().equals(match.getId()) && level4.getName().equals(match.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if match exists in level2s.
|
||||
*/
|
||||
private boolean contains(Set<Level2> level2s, Level2 match) {
|
||||
for (Level2 level2 : level2s) {
|
||||
if (level2.getId().equals(match.getId()) && level2.getName().equals(match.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class TestQueryFindPagedList extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class).findPagedList(0, 3);
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class).findPagedList(0, 4);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TestQueryFindPagedList extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class).findPagedList(0, 3);
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class).findPagedList(0, 5);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
@@ -98,7 +98,7 @@ public class TestQueryFindPagedList extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class).findPagedList(0, 3);
|
||||
PagedList<Order> pagedList = Ebean.find(Order.class).findPagedList(0, 6);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user