mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Remove Subclassing/Dynamic Proxy support - beans must be enhanced
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -138,22 +136,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
public <T> T createEntityBean(Class<T> type);
|
||||
|
||||
/**
|
||||
* Create a ObjectInputStream that can be used to deserialise "Proxy" or
|
||||
* "SubClassed" entity beans.
|
||||
* <p>
|
||||
* This is NOT required when entity beans are "Enhanced" (via java agent or
|
||||
* ant task etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* The reason this is needed to deserialise "Proxy" beans is because Ebean
|
||||
* creates the "Proxy/SubClass" classes in a class loader - and generally the
|
||||
* class loader deserialising the inputStream is not aware of these other
|
||||
* classes.
|
||||
* </p>
|
||||
*/
|
||||
public ObjectInputStream createProxyObjectInputStream(InputStream is);
|
||||
|
||||
/**
|
||||
* Create a CsvReader for a given beanType.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -959,23 +957,6 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> setDistinct(boolean isDistinct);
|
||||
|
||||
/**
|
||||
* Set this to true and the beans and collections returned will be plain
|
||||
* classes rather than Ebean generated dynamic subclasses etc.
|
||||
* <p>
|
||||
* This is *ONLY* relevant when you are not using enhancement (and using
|
||||
* dynamic subclasses instead).
|
||||
* </p>
|
||||
* <p>
|
||||
* Alternatively you can globally set the mode using ebean.vanillaMode=true in
|
||||
* ebean.properties or {@link ServerConfig#setVanillaMode(boolean)}.
|
||||
* </p>
|
||||
*
|
||||
* @see ServerConfig#setVanillaMode(boolean)
|
||||
* @see ServerConfig#setVanillaRefMode(boolean)
|
||||
*/
|
||||
public Query<T> setVanillaMode(boolean vanillaMode);
|
||||
|
||||
/**
|
||||
* Return the first row value.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Marker interface for classes enhanced to support Transactional methods.
|
||||
*/
|
||||
public interface EnhancedTransactional {
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.avaje.ebean.bean;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
@@ -536,27 +535,6 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is ONLY used for subclass entity beans.
|
||||
* <p>
|
||||
* This is not used when entity bean classes are enhanced via javaagent or ant
|
||||
* etc - only when a subclass is generated.
|
||||
* </p>
|
||||
* Returns a Serializable instance that is either the 'byte code generated'
|
||||
* object or a 'Vanilla' copy of this bean depending on
|
||||
* SerializeControl.isVanillaBeans().
|
||||
*/
|
||||
public Object writeReplaceIntercept() throws ObjectStreamException {
|
||||
|
||||
if (!SerializeControl.isVanillaBeans()) {
|
||||
return owner;
|
||||
}
|
||||
|
||||
// creates a plain vanilla object and
|
||||
// copies the values from the owner
|
||||
return owner._ebean_createCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if two objects are equal.
|
||||
*/
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* This is ONLY used for <b>subclassed</b> entity beans.
|
||||
* <p>
|
||||
* This is NOT USED for entity beans that are enhanced via a javaagent or ant
|
||||
* task etc. This is only used when the entity beans are created as a subclass
|
||||
* of the original class.
|
||||
* </p>
|
||||
* <p>
|
||||
* Allows the developer to control whether beans and collections are serialized
|
||||
* to plain 'vanilla' classes or left in byte code generated subclasses.
|
||||
* <p>
|
||||
* Vanilla beans are beans that have plain ordinary classes as opposed to
|
||||
* specially generated classes that Ebean creates. Ebean creates classes (using
|
||||
* ASM) to support lazy loading (reference beans) and concurrency checking etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* SerializeControl gives you the ability to control whether an object graph is
|
||||
* serialized to plain 'vanilla' objects or in the special byte code generated
|
||||
* form. There are pros and cons for both approaches depending on whether you
|
||||
* want to support "FULL" concurrency checking and lazy loading when the object
|
||||
* graph is deserialized.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that BeanMap, BeanList and BeanSet are not byte code generated. They are
|
||||
* ordinary classes. However you may wish to have these serialized to the
|
||||
* underlying List Set and Map implementations for the benefit that they can be
|
||||
* deserialised in a JVM without <em>ANY</em> ebean code at all.
|
||||
* </p>
|
||||
*/
|
||||
public class SerializeControl {
|
||||
|
||||
private static final String BEANS = "com.avaje.ebean.vanillabeans";
|
||||
|
||||
private static final String COLLECTIONS = "com.avaje.ebean.vanillacollections";
|
||||
|
||||
private static Boolean getDefault(String key, Boolean dflt) {
|
||||
String val = System.getProperty(key);
|
||||
if (val != null) {
|
||||
return val.equalsIgnoreCase("true");
|
||||
}
|
||||
return dflt;
|
||||
}
|
||||
|
||||
private static ThreadLocal<Boolean> vanillaBeans = new ThreadLocal<Boolean>() {
|
||||
protected synchronized Boolean initialValue() {
|
||||
return getDefault(BEANS, Boolean.TRUE);
|
||||
}
|
||||
};
|
||||
|
||||
private static ThreadLocal<Boolean> vanillaCollections = new ThreadLocal<Boolean>() {
|
||||
protected synchronized Boolean initialValue() {
|
||||
return getDefault(COLLECTIONS, Boolean.TRUE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the JVM wide default for Beans.
|
||||
*/
|
||||
public static void setDefaultForBeans(boolean vanillaOn) {
|
||||
Boolean b = Boolean.valueOf(vanillaOn);
|
||||
System.setProperty(BEANS, b.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JVM wide default for Collections.
|
||||
*/
|
||||
public static void setDefaultForCollections(boolean vanillaOn) {
|
||||
Boolean b = Boolean.valueOf(vanillaOn);
|
||||
System.setProperty(COLLECTIONS, b.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the mode for beans and collections back to the JVM wide default
|
||||
* setting.
|
||||
*/
|
||||
public static void resetToDefault() {
|
||||
Boolean beans = getDefault(BEANS, Boolean.FALSE);
|
||||
setVanillaBeans(beans);
|
||||
|
||||
Boolean coll = getDefault(COLLECTIONS, Boolean.FALSE);
|
||||
setVanillaCollections(coll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode for both Beans and Collections.
|
||||
*/
|
||||
public static void setVanilla(boolean vanillaOn) {
|
||||
if (vanillaOn) {
|
||||
vanillaBeans.set(Boolean.TRUE);
|
||||
vanillaCollections.set(Boolean.TRUE);
|
||||
} else {
|
||||
vanillaBeans.set(Boolean.FALSE);
|
||||
vanillaCollections.set(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if beans are serialized to Vanilla as opposed to byte code
|
||||
* generated subclasses.
|
||||
*/
|
||||
public static boolean isVanillaBeans() {
|
||||
return (Boolean) vanillaBeans.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether beans should be serialized to Vanilla as opposed to byte code
|
||||
* generated subclasses.
|
||||
*/
|
||||
public static void setVanillaBeans(boolean vanillaOn) {
|
||||
vanillaBeans.set(vanillaOn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if collections are serialized to be plain Lists Sets or Maps as
|
||||
* opposed to BeanList, BeanMap or BeanSet.
|
||||
*/
|
||||
public static boolean isVanillaCollections() {
|
||||
return (Boolean) vanillaCollections.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether collections should be serialized to Vanilla Lists Sets or Maps
|
||||
* (instead of BeanList, BeanMap or BeanSet).
|
||||
*/
|
||||
public static void setVanillaCollections(boolean vanillaOn) {
|
||||
vanillaCollections.set(vanillaOn);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -11,7 +10,6 @@ import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.SerializeControl;
|
||||
|
||||
/**
|
||||
* List capable of lazy loading.
|
||||
@@ -46,20 +44,6 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
super(loader, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
Object readResolve() throws ObjectStreamException {
|
||||
if (SerializeControl.isVanillaCollections()) {
|
||||
return list;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Object writeReplace() throws ObjectStreamException {
|
||||
if (SerializeControl.isVanillaCollections()) {
|
||||
return list;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addBean(Object bean) {
|
||||
list.add((E) bean);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@@ -9,7 +8,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.SerializeControl;
|
||||
|
||||
/**
|
||||
* Map capable of lazy loading.
|
||||
@@ -39,20 +37,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
super(ebeanServer, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
Object readResolve() throws ObjectStreamException {
|
||||
if (SerializeControl.isVanillaCollections()) {
|
||||
return map;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Object writeReplace() throws ObjectStreamException {
|
||||
if (SerializeControl.isVanillaCollections()) {
|
||||
return map;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void internalAdd(Object bean) {
|
||||
throw new RuntimeException("Not allowed for map");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
@@ -9,7 +8,6 @@ import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.SerializeControl;
|
||||
|
||||
/**
|
||||
* Set capable of lazy loading.
|
||||
@@ -40,20 +38,6 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
super(loader, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
Object readResolve() throws ObjectStreamException {
|
||||
if (SerializeControl.isVanillaCollections()) {
|
||||
return set;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Object writeReplace() throws ObjectStreamException {
|
||||
if (SerializeControl.isVanillaCollections()) {
|
||||
return set;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addBean(Object bean) {
|
||||
set.add((E) bean);
|
||||
|
||||
@@ -5,10 +5,8 @@ import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.EbeanServerFactory;
|
||||
import com.avaje.ebean.LogLevel;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.annotation.Encrypted;
|
||||
import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
@@ -214,24 +212,6 @@ public class ServerConfig {
|
||||
|
||||
private ServerCacheManager serverCacheManager;
|
||||
|
||||
/**
|
||||
* Set this to true when by default vanilla objects should be returned from
|
||||
* queries rather than dynamic subclasses etc. Only relevant when not using
|
||||
* enhancement (using dynamic subclasses).
|
||||
*/
|
||||
private boolean vanillaMode;
|
||||
|
||||
/**
|
||||
* Controls whether the {@link EbeanServer#getReference(Class, Object)} method
|
||||
* returns vanilla objects or not.
|
||||
*/
|
||||
private boolean vanillaRefMode;
|
||||
|
||||
/**
|
||||
* Set to false to require enhancement to be used. Defaults to true.
|
||||
*/
|
||||
private boolean allowSubclassing = true;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an
|
||||
* EbeanServer.
|
||||
@@ -466,56 +446,6 @@ public class ServerConfig {
|
||||
this.serverCacheManager = serverCacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if by default queries should return 'vanilla' objects rather
|
||||
* than dynamic subclasses.
|
||||
* <p>
|
||||
* This setting is not relevant when using enhancement (only when using
|
||||
* dynamic subclasses).
|
||||
* </p>
|
||||
*/
|
||||
public boolean isVanillaMode() {
|
||||
return vanillaMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true if by default queries should return 'vanilla' objects
|
||||
* rather than dynamic subclasses.
|
||||
* <p>
|
||||
* This setting is not relevant when using enhancement (only when using
|
||||
* dynamic subclasses).
|
||||
* </p>
|
||||
* <p>
|
||||
* Alternatively you can set this on a specific query via
|
||||
* {@link Query#setVanillaMode(boolean)}.
|
||||
* </p>
|
||||
*
|
||||
* @see #setVanillaRefMode(boolean)
|
||||
* @see Query#setVanillaMode(boolean)
|
||||
*/
|
||||
public void setVanillaMode(boolean vanillaMode) {
|
||||
this.vanillaMode = vanillaMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@link EbeanServer#getReference(Class, Object)} should
|
||||
* return vanilla objects or not.
|
||||
*
|
||||
* @see #setVanillaMode(boolean)
|
||||
* @see Query#setVanillaMode(boolean)
|
||||
*/
|
||||
public boolean isVanillaRefMode() {
|
||||
return vanillaRefMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true if you want
|
||||
* {@link EbeanServer#getReference(Class, Object)} to return vanilla objects.
|
||||
*/
|
||||
public void setVanillaRefMode(boolean vanillaRefMode) {
|
||||
this.vanillaRefMode = vanillaRefMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the log level used for "subclassing" enhancement.
|
||||
*/
|
||||
@@ -1151,20 +1081,6 @@ public class ServerConfig {
|
||||
this.updateChangesOnly = updateChangesOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false to require enhancement to be used. Defaults to true.
|
||||
*/
|
||||
public void setAllowSubclassing(boolean allowSubclassing) {
|
||||
this.allowSubclassing = allowSubclassing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this config supports subclassed entities.
|
||||
*/
|
||||
public boolean isAllowSubclassing() {
|
||||
return allowSubclassing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource directory.
|
||||
*/
|
||||
@@ -1421,9 +1337,6 @@ public class ServerConfig {
|
||||
packages = getSearchJarsPackages(packagesProp);
|
||||
}
|
||||
|
||||
allowSubclassing = p.getBoolean("allowSubclassing", true);
|
||||
vanillaMode = p.getBoolean("vanillaMode", false);
|
||||
vanillaRefMode = p.getBoolean("vanillaRefMode", false);
|
||||
updateChangesOnly = p.getBoolean("updateChangesOnly", true);
|
||||
|
||||
boolean batchMode = p.getBoolean("batch.mode", false);
|
||||
|
||||
@@ -33,11 +33,6 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
|
||||
* Return true if UpdateNullProperties defaults to true for stateless updates.
|
||||
*/
|
||||
public boolean isDefaultUpdateNullProperties();
|
||||
|
||||
/**
|
||||
* Return true if vanilla beans should be returned by queries by default.
|
||||
*/
|
||||
public boolean isVanillaMode();
|
||||
|
||||
/**
|
||||
* Return the DatabasePlatform for this server.
|
||||
|
||||
@@ -522,11 +522,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
public boolean isDistinct();
|
||||
|
||||
/**
|
||||
* Return true if this query should build and return vanilla objects.
|
||||
*/
|
||||
public boolean isVanillaMode(boolean serverDefaultVanillaMode);
|
||||
|
||||
/**
|
||||
* Set default select clauses where none have been explicitly defined.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ public class CachedBeanDataFromBean {
|
||||
sharableBean = bean;
|
||||
} else {
|
||||
// create a readOnly sharable instance by copying the data
|
||||
sharableBean = desc.createBean(false);
|
||||
sharableBean = desc.createBean();
|
||||
BeanProperty[] propertiesId = desc.propertiesId();
|
||||
for (int i = 0; i < propertiesId.length; i++) {
|
||||
Object v = propertiesId[i].getValue(bean);
|
||||
|
||||
@@ -34,13 +34,10 @@ public class DefaultBeanLoader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultBeanLoader.class);
|
||||
|
||||
private final DebugLazyLoad debugLazyLoad;
|
||||
|
||||
private final DefaultServer server;
|
||||
|
||||
protected DefaultBeanLoader(DefaultServer server, DebugLazyLoad debugLazyLoad) {
|
||||
protected DefaultBeanLoader(DefaultServer server) {
|
||||
this.server = server;
|
||||
this.debugLazyLoad = debugLazyLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,17 +170,13 @@ public class DefaultBeanLoader {
|
||||
|
||||
private void loadManyInternal(Object parentBean, String propertyName, Transaction t, boolean refresh, ObjectGraphNode node, boolean onlyIds) {
|
||||
|
||||
boolean vanilla = (parentBean instanceof EntityBean == false);
|
||||
|
||||
EntityBeanIntercept ebi = null;
|
||||
PersistenceContext pc = null;
|
||||
BeanCollection<?> beanCollection = null;
|
||||
ExpressionList<?> filterMany = null;
|
||||
|
||||
if (!vanilla) {
|
||||
ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
}
|
||||
ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>) parentDesc.getBeanProperty(propertyName);
|
||||
@@ -201,13 +194,13 @@ public class DefaultBeanLoader {
|
||||
pc.put(parentId, parentBean);
|
||||
}
|
||||
|
||||
boolean useManyIdCache = !vanilla && beanCollection != null && parentDesc.cacheIsUseManyId();
|
||||
boolean useManyIdCache = beanCollection != null && parentDesc.cacheIsUseManyId();
|
||||
if (useManyIdCache) {
|
||||
Boolean readOnly = null;
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
readOnly = Boolean.TRUE;
|
||||
}
|
||||
if (parentDesc.cacheLoadMany(many, beanCollection, parentId, readOnly, false)) {
|
||||
if (parentDesc.cacheLoadMany(many, beanCollection, parentId, readOnly)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +209,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
if (refresh) {
|
||||
// populate a new collection
|
||||
Object emptyCollection = many.createEmpty(vanilla);
|
||||
Object emptyCollection = many.createEmpty(false);
|
||||
many.setValue(parentBean, emptyCollection);
|
||||
query.setLoadDescription("+refresh", null);
|
||||
} else {
|
||||
@@ -245,7 +238,6 @@ public class DefaultBeanLoader {
|
||||
query.setMode(Mode.LAZYLOAD_MANY);
|
||||
query.setLazyLoadManyPath(many.getName());
|
||||
query.setPersistenceContext(pc);
|
||||
query.setVanillaMode(vanilla);
|
||||
|
||||
if (ebi != null) {
|
||||
if (ebi.isReadOnly()) {
|
||||
@@ -370,15 +362,9 @@ public class DefaultBeanLoader {
|
||||
|
||||
private void refreshBeanInternal(Object bean, SpiQuery.Mode mode) {
|
||||
|
||||
boolean vanilla = (bean instanceof EntityBean == false);
|
||||
|
||||
EntityBeanIntercept ebi = null;
|
||||
PersistenceContext pc = null;
|
||||
|
||||
if (!vanilla) {
|
||||
ebi = ((EntityBean) bean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
}
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) bean)._ebean_getIntercept();;
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptor(bean.getClass());
|
||||
Object id = desc.getId(bean);
|
||||
@@ -429,7 +415,6 @@ public class DefaultBeanLoader {
|
||||
if (mode.equals(SpiQuery.Mode.REFRESH_BEAN)) {
|
||||
query.setUseCache(false);
|
||||
}
|
||||
query.setVanillaMode(vanilla);
|
||||
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -138,13 +135,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
private final boolean defaultDeleteMissingChildren;
|
||||
private final boolean defaultUpdateNullProperties;
|
||||
|
||||
/**
|
||||
* Set to true if vanilla objects should be returned by default from queries
|
||||
* (with dynamic subclassing).
|
||||
*/
|
||||
private final boolean vanillaMode;
|
||||
private final boolean vanillaRefMode;
|
||||
|
||||
/**
|
||||
* Handles the save, delete, updateSql CallableSql.
|
||||
*/
|
||||
@@ -210,9 +200,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
*/
|
||||
public DefaultServer(InternalConfiguration config, ServerCacheManager cache) {
|
||||
|
||||
this.vanillaMode = config.getServerConfig().isVanillaMode();
|
||||
this.vanillaRefMode = config.getServerConfig().isVanillaRefMode();
|
||||
|
||||
this.serverCacheManager = cache;
|
||||
this.pstmtBatch = config.getPstmtBatch();
|
||||
this.databasePlatform = config.getDatabasePlatform();
|
||||
@@ -245,7 +232,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
this.autoFetchManager = config.createAutoFetchManager(this);
|
||||
this.adminAutofetch = new MAdminAutofetch(autoFetchManager);
|
||||
|
||||
this.beanLoader = new DefaultBeanLoader(this, config.getDebugLazyLoad());
|
||||
this.beanLoader = new DefaultBeanLoader(this);
|
||||
this.jsonContext = config.createJsonContext(this);
|
||||
|
||||
loadAndInitializePlugins(config);
|
||||
@@ -290,10 +277,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return defaultUpdateNullProperties;
|
||||
}
|
||||
|
||||
public boolean isVanillaMode() {
|
||||
return vanillaMode;
|
||||
}
|
||||
|
||||
public int getLazyLoadBatchSize() {
|
||||
return lazyLoadBatchSize;
|
||||
}
|
||||
@@ -410,8 +393,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
if (bean instanceof EntityBean) {
|
||||
return new DefaultBeanState((EntityBean) bean);
|
||||
}
|
||||
// if using "subclassing" (not enhancement) this will
|
||||
// return null for 'vanilla' instances (not subclassed)
|
||||
// Not an entity bean
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -563,15 +545,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return (T) desc.createEntityBean();
|
||||
}
|
||||
|
||||
public ObjectInputStream createProxyObjectInputStream(InputStream is) {
|
||||
|
||||
try {
|
||||
return new ProxyBeanObjectInputStream(is, this);
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Reference bean.
|
||||
* <p>
|
||||
@@ -629,7 +602,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
} else {
|
||||
// use the default reference options
|
||||
ref = desc.createReference(vanillaRefMode, null, id, null);
|
||||
ref = desc.createReference(null, id, null);
|
||||
}
|
||||
|
||||
if (ctx != null && (ref instanceof EntityBean)) {
|
||||
@@ -1139,25 +1112,20 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return null;
|
||||
}
|
||||
|
||||
// boolean readOnly = beanDescriptor.calculateReadOnly(query.isReadOnly());
|
||||
boolean vanilla = query.isVanillaMode(vanillaMode);
|
||||
Object cachedBean = beanDescriptor.cacheGetBean(query.getId(), vanilla, query.isReadOnly());
|
||||
Object cachedBean = beanDescriptor.cacheGetBean(query.getId(), query.isReadOnly());
|
||||
if (cachedBean != null) {
|
||||
if (context == null) {
|
||||
context = new DefaultPersistenceContext();
|
||||
|
||||
}
|
||||
context.put(query.getId(), cachedBean);
|
||||
if (!vanilla) {
|
||||
|
||||
DLoadContext loadContext = new DLoadContext(this, beanDescriptor, query.isReadOnly(), false, null, false);
|
||||
loadContext.setPersistenceContext(context);
|
||||
DLoadContext loadContext = new DLoadContext(this, beanDescriptor, query.isReadOnly(), false, null, false);
|
||||
loadContext.setPersistenceContext(context);
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) cachedBean)._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(context);
|
||||
loadContext.register(null, ebi);
|
||||
|
||||
}
|
||||
EntityBeanIntercept ebi = ((EntityBean) cachedBean)._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(context);
|
||||
loadContext.register(null, ebi);
|
||||
}
|
||||
|
||||
return (T) cachedBean;
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassManager;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
@@ -54,8 +53,6 @@ public class InternalConfiguration {
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final SubClassManager subClassManager;
|
||||
|
||||
private final DeployInherit deployInherit;
|
||||
|
||||
private final ResourceManager resourceManager;
|
||||
@@ -105,8 +102,6 @@ public class InternalConfiguration {
|
||||
this.bootupClasses = bootupClasses;
|
||||
this.expressionFactory = new DefaultExpressionFactory();
|
||||
|
||||
this.subClassManager = new SubClassManager(serverConfig);
|
||||
|
||||
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
|
||||
this.binder = new Binder(typeManager);
|
||||
|
||||
@@ -215,10 +210,6 @@ public class InternalConfiguration {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public SubClassManager getSubClassManager() {
|
||||
return subClassManager;
|
||||
}
|
||||
|
||||
public DeployInherit getDeployInherit() {
|
||||
return deployInherit;
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
private final boolean vanillaMode;
|
||||
|
||||
private final BeanFinder<T> finder;
|
||||
|
||||
private final LoadContext graphContext;
|
||||
@@ -74,7 +72,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
this.finder = beanDescriptor.getBeanFinder();
|
||||
this.queryEngine = queryEngine;
|
||||
this.query = query;
|
||||
this.vanillaMode = query.isVanillaMode(server.isVanillaMode());
|
||||
this.readOnly = query.isReadOnly();
|
||||
|
||||
this.graphContext = new DLoadContext(ebeanServer, beanDescriptor, readOnly, query);
|
||||
@@ -226,11 +223,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
public boolean isFindById() {
|
||||
return query.getType() == Type.BEAN;
|
||||
}
|
||||
|
||||
public boolean isVanillaMode() {
|
||||
return vanillaMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
@@ -269,8 +262,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<T> findList() {
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (List<T>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
return (List<T>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,8 +270,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<?> findSet() {
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (Set<T>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
return (Set<T>)queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,8 +287,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
}
|
||||
BeanCollection<T> bc = queryEngine.findMany(this);
|
||||
return (Map<?, ?>) (vanillaMode ? bc.getActualCollection() : bc);
|
||||
return (Map<?, ?>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
public SpiQuery.Type getQueryType() {
|
||||
@@ -377,14 +367,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
|
||||
// TODO: Sort out returning BeanCollection from L2 cache
|
||||
return null;
|
||||
|
||||
// BeanCollection<T> bc = beanDescriptor.queryCacheGet(cacheKey);
|
||||
// if (bc != null && Boolean.FALSE.equals(query.isReadOnly())) {
|
||||
// // Explicit readOnly=false for query cache
|
||||
// CopyContext ctx = new CopyContext(vanillaMode, false);
|
||||
// return new CopyBeanCollection<T>(bc, beanDescriptor, ctx, 5).copy();
|
||||
// }
|
||||
// return bc;
|
||||
}
|
||||
|
||||
public void putToQueryCache(BeanCollection<T> queryResult) {
|
||||
|
||||
@@ -53,11 +53,6 @@ public class PersistRequestBean<T> extends PersistRequest implements BeanPersist
|
||||
|
||||
protected final boolean isDirty;
|
||||
|
||||
/**
|
||||
* True if this is a vanilla bean.
|
||||
*/
|
||||
protected final boolean vanilla;
|
||||
|
||||
/**
|
||||
* The bean being persisted.
|
||||
*/
|
||||
@@ -113,8 +108,6 @@ public class PersistRequestBean<T> extends PersistRequest implements BeanPersist
|
||||
this.concurrencyMode = concurrencyMode;
|
||||
this.loadedProps = updateProps;
|
||||
this.changedProps = updateProps;
|
||||
|
||||
this.vanilla = true;
|
||||
this.isDirty = true;
|
||||
this.oldValues = bean;
|
||||
if (bean instanceof EntityBean) {
|
||||
@@ -137,41 +130,24 @@ public class PersistRequestBean<T> extends PersistRequest implements BeanPersist
|
||||
|
||||
this.controller = beanDescriptor.getPersistController();
|
||||
this.concurrencyMode = beanDescriptor.getConcurrencyMode();
|
||||
|
||||
if (bean instanceof EntityBean) {
|
||||
this.intercept = ((EntityBean) bean)._ebean_getIntercept();
|
||||
if (intercept.isReference()) {
|
||||
// allowed to delete reference objects
|
||||
// with no concurrency checking
|
||||
this.concurrencyMode = ConcurrencyMode.NONE;
|
||||
}
|
||||
// this is ok to not use isNewOrDirty() as used for updates only
|
||||
this.isDirty = intercept.isDirty();
|
||||
if (!isDirty) {
|
||||
this.changedProps = intercept.getChangedProps();
|
||||
} else {
|
||||
// merge changed properties on the bean with changed embedded beans
|
||||
Set<String> beanChangedProps = intercept.getChangedProps();
|
||||
Set<String> dirtyEmbedded = beanDescriptor.getDirtyEmbeddedProperties(bean);
|
||||
this.changedProps = mergeChangedProperties(beanChangedProps, dirtyEmbedded);
|
||||
}
|
||||
this.loadedProps = intercept.getLoadedProps();
|
||||
this.oldValues = (T) intercept.getOldValues();
|
||||
this.vanilla = false;
|
||||
|
||||
} else {
|
||||
// have to assume the vanilla bean is dirty
|
||||
this.vanilla = true;
|
||||
this.isDirty = true;
|
||||
this.loadedProps = null;
|
||||
this.changedProps = null;
|
||||
this.intercept = null;
|
||||
|
||||
// degrade concurrency checking to none for vanilla bean
|
||||
if (concurrencyMode.equals(ConcurrencyMode.ALL)) {
|
||||
this.concurrencyMode = ConcurrencyMode.NONE;
|
||||
}
|
||||
this.intercept = ((EntityBean) bean)._ebean_getIntercept();
|
||||
if (intercept.isReference()) {
|
||||
// allowed to delete reference objects
|
||||
// with no concurrency checking
|
||||
this.concurrencyMode = ConcurrencyMode.NONE;
|
||||
}
|
||||
// this is ok to not use isNewOrDirty() as used for updates only
|
||||
this.isDirty = intercept.isDirty();
|
||||
if (!isDirty) {
|
||||
this.changedProps = intercept.getChangedProps();
|
||||
} else {
|
||||
// merge changed properties on the bean with changed embedded beans
|
||||
Set<String> beanChangedProps = intercept.getChangedProps();
|
||||
Set<String> dirtyEmbedded = beanDescriptor.getDirtyEmbeddedProperties(bean);
|
||||
this.changedProps = mergeChangedProperties(beanChangedProps, dirtyEmbedded);
|
||||
}
|
||||
this.loadedProps = intercept.getLoadedProps();
|
||||
this.oldValues = (T) intercept.getOldValues();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -632,7 +608,7 @@ public class PersistRequestBean<T> extends PersistRequest implements BeanPersist
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDynamicUpdateSql() {
|
||||
return !vanilla && beanDescriptor.isUpdateChangesOnly() || (loadedProps != null);
|
||||
return beanDescriptor.isUpdateChangesOnly() || (loadedProps != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -666,7 +642,9 @@ public class PersistRequestBean<T> extends PersistRequest implements BeanPersist
|
||||
* update.
|
||||
*/
|
||||
public boolean hasChanged(BeanProperty prop) {
|
||||
|
||||
if (changedProps == null) {
|
||||
return false;
|
||||
}
|
||||
return changedProps.contains(prop.getName());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.bean.SerializeControl;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassUtil;
|
||||
|
||||
/**
|
||||
* Read an ObjectInputStream potentially containing "proxy" / "subclassed"
|
||||
* entity objects.
|
||||
* <p>
|
||||
* This does not need to be used for "Enhanced" beans... but if you want to
|
||||
* deserialise "proxy" / "subclassed" beans you need to use this
|
||||
* ProxyBeanObjectInputStream. The reason is because it is required to resolve
|
||||
* the class (The class with the $$EntityBean suffix). As this class is in
|
||||
* another class loader typically as plain ObjectInputStream is unable to resolve
|
||||
* the class - and hence we need to use this ProxyBeanObjectInputStream.
|
||||
* </p>
|
||||
*/
|
||||
public class ProxyBeanObjectInputStream extends ObjectInputStream {
|
||||
|
||||
private final SpiEbeanServer ebeanServer;
|
||||
|
||||
/**
|
||||
* Create with a given InputStream and EbeanServer.
|
||||
* <p>
|
||||
* The EbeanServer should be the one that created the 'proxy' classes that
|
||||
* were serialised.
|
||||
* </p>
|
||||
*/
|
||||
public ProxyBeanObjectInputStream(InputStream in, EbeanServer ebeanServer)
|
||||
throws IOException {
|
||||
|
||||
super(in);
|
||||
this.ebeanServer = (SpiEbeanServer) ebeanServer;
|
||||
SerializeControl.setVanilla(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* close and reset the serialization mode.
|
||||
* <p>
|
||||
* uses SerializeControl.resetToDefault().
|
||||
* </p>
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
SerializeControl.resetToDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the generated Class potentially using reading the embedded
|
||||
* MethodInfo.
|
||||
*/
|
||||
protected Class<?> resolveGenerated(ObjectStreamClass desc)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
String className = desc.getName();
|
||||
|
||||
String vanillaClassName = SubClassUtil.getSuperClassName(className);
|
||||
Class<?> vanillaClass = ClassUtil.forName(vanillaClassName, this.getClass());
|
||||
|
||||
BeanDescriptor<?> d = ebeanServer.getBeanDescriptor(vanillaClass);
|
||||
if (d == null) {
|
||||
String msg = "Could not find BeanDescriptor for "+ vanillaClassName;
|
||||
throw new IOException(msg);
|
||||
} else {
|
||||
return d.getFactoryType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks for generated subclasses and handles them appropriately.
|
||||
*/
|
||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
|
||||
ClassNotFoundException {
|
||||
|
||||
String className = desc.getName();
|
||||
if (SubClassUtil.isSubClass(className)) {
|
||||
return resolveGenerated(desc);
|
||||
}
|
||||
|
||||
return super.resolveClass(desc);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -87,9 +87,9 @@ public class XmlConfigLoader {
|
||||
if (classPath.isDirectory()) {
|
||||
checkDir(searchFor, xmlList, classPath);
|
||||
|
||||
} else if (classPath.getName().endsWith(".jar")) {
|
||||
} else if (classPath.getName().endsWith(".jar") || classPath.getName().endsWith(".war")) {
|
||||
checkJar(searchFor, xmlList, classPath);
|
||||
|
||||
|
||||
} else {
|
||||
// this is not expected
|
||||
String msg = "Not a Jar or Directory? " + classPath.getAbsolutePath();
|
||||
|
||||
@@ -936,7 +936,7 @@ public class BeanDescriptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cacheLoadMany(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly, boolean vanilla) {
|
||||
public boolean cacheLoadMany(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
|
||||
|
||||
CachedManyIds ids = cacheGetCachedManyIds(parentId, many.getName());
|
||||
if (ids == null) {
|
||||
@@ -953,7 +953,7 @@ public class BeanDescriptor<T> {
|
||||
bc.checkEmptyLazyLoad();
|
||||
for (int i = 0; i < idList.size(); i++) {
|
||||
Object id = idList.get(i);
|
||||
Object refBean = targetDescriptor.createReference(vanilla, readOnly, id, null);
|
||||
Object refBean = targetDescriptor.createReference(readOnly, id, null);
|
||||
EntityBeanIntercept refEbi = ((EntityBean) refBean)._ebean_getIntercept();
|
||||
|
||||
many.add(bc, refBean);
|
||||
@@ -999,22 +999,22 @@ public class BeanDescriptor<T> {
|
||||
* Return a bean from the bean cache.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T cacheGetBean(Object id, boolean vanilla, Boolean readOnly) {
|
||||
public T cacheGetBean(Object id, Boolean readOnly) {
|
||||
|
||||
CachedBeanData d = (CachedBeanData) getBeanCache().get(id);
|
||||
if (d == null) {
|
||||
return null;
|
||||
}
|
||||
if (cacheSharableBeans && !vanilla && !Boolean.FALSE.equals(readOnly)) {
|
||||
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
|
||||
Object bean = d.getSharableBean();
|
||||
if (bean != null) {
|
||||
return (T) bean;
|
||||
}
|
||||
}
|
||||
|
||||
T bean = (T) createBean(vanilla);
|
||||
T bean = (T) createBean();
|
||||
convertSetId(id, bean);
|
||||
if (!vanilla && Boolean.TRUE.equals(readOnly)) {
|
||||
if (Boolean.TRUE.equals(readOnly)) {
|
||||
((EntityBean) bean)._ebean_getIntercept().setReadOnly(true);
|
||||
}
|
||||
|
||||
@@ -1306,20 +1306,10 @@ public class BeanDescriptor<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an EntityBean or "Vanilla" bean depending on the flag.
|
||||
* Create an EntityBean.
|
||||
*/
|
||||
public Object createBean(boolean vanillaMode) {
|
||||
return vanillaMode ? createVanillaBean() : createEntityBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a plain vanilla object.
|
||||
* <p>
|
||||
* Used for EmbeddedId Bean construction.
|
||||
* </p>
|
||||
*/
|
||||
public Object createVanillaBean() {
|
||||
return beanReflect.createVanillaBean();
|
||||
public Object createBean() {
|
||||
return createEntityBean();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1341,9 +1331,9 @@ public class BeanDescriptor<T> {
|
||||
* Create a reference bean based on the id.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T createReference(boolean vanillaMode, Boolean readOnly, Object id, Object parent) {
|
||||
public T createReference(Boolean readOnly, Object id, Object parent) {
|
||||
|
||||
if (cacheSharableBeans && !vanillaMode && !Boolean.FALSE.equals(readOnly)) {
|
||||
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
|
||||
CachedBeanData d = (CachedBeanData) getBeanCache().get(id);
|
||||
if (d != null) {
|
||||
Object shareableBean = d.getSharableBean();
|
||||
@@ -1353,26 +1343,24 @@ public class BeanDescriptor<T> {
|
||||
}
|
||||
}
|
||||
try {
|
||||
Object bean = createBean(vanillaMode);
|
||||
Object bean = createBean();
|
||||
|
||||
convertSetId(id, bean);
|
||||
|
||||
if (!vanillaMode) {
|
||||
EntityBean eb = (EntityBean) bean;
|
||||
EntityBean eb = (EntityBean) bean;
|
||||
|
||||
EntityBeanIntercept ebi = eb._ebean_getIntercept();
|
||||
ebi.setBeanLoaderByServerName(ebeanServer.getName());
|
||||
EntityBeanIntercept ebi = eb._ebean_getIntercept();
|
||||
ebi.setBeanLoaderByServerName(ebeanServer.getName());
|
||||
|
||||
if (parent != null) {
|
||||
// Special case for a OneToOne ... parent
|
||||
// needs to be added to context prior to query
|
||||
ebi.setParentBean(parent);
|
||||
}
|
||||
|
||||
// Note: not creating proxies for many's...
|
||||
ebi.setReference();
|
||||
if (parent != null) {
|
||||
// Special case for a OneToOne ... parent
|
||||
// needs to be added to context prior to query
|
||||
ebi.setParentBean(parent);
|
||||
}
|
||||
|
||||
// Note: not creating proxies for many's...
|
||||
ebi.setReference();
|
||||
|
||||
return (T) bean;
|
||||
|
||||
} catch (Exception ex) {
|
||||
@@ -2209,17 +2197,6 @@ public class BeanDescriptor<T> {
|
||||
return propertyFirstVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this an Insert (rather than Update) on a non-enhanced bean.
|
||||
*/
|
||||
public boolean isVanillaInsert(Object bean) {
|
||||
if (propertyFirstVersion == null) {
|
||||
return true;
|
||||
}
|
||||
Object versionValue = propertyFirstVersion.getValue(bean);
|
||||
return DmlUtil.isNullOrZero(versionValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is an Update (rather than insert) given that the bean
|
||||
* is involved in a stateless update.
|
||||
|
||||
@@ -14,6 +14,9 @@ import java.util.Set;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.RawSqlBuilder;
|
||||
@@ -60,11 +63,7 @@ import com.avaje.ebeaninternal.server.reflect.BeanReflectFactory;
|
||||
import com.avaje.ebeaninternal.server.reflect.BeanReflectGetter;
|
||||
import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter;
|
||||
import com.avaje.ebeaninternal.server.reflect.EnhanceBeanReflectFactory;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassManager;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassUtil;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Creates BeanDescriptors.
|
||||
@@ -98,8 +97,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private final BeanQueryAdapterManager beanQueryAdapterManager;
|
||||
|
||||
private final SubClassManager subClassManager;
|
||||
|
||||
private final NamingConvention namingConvention;
|
||||
|
||||
private final DeployCreateProperties createProperties;
|
||||
@@ -153,8 +150,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
private final boolean allowSubclassing;
|
||||
|
||||
/**
|
||||
* Create for a given database dbConfig.
|
||||
*/
|
||||
@@ -172,7 +167,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
this.bootupClasses = config.getBootupClasses();
|
||||
this.createProperties = config.getDeployCreateProperties();
|
||||
this.subClassManager = config.getSubClassManager();
|
||||
this.typeManager = config.getTypeManager();
|
||||
this.namingConvention = config.getServerConfig().getNamingConvention();
|
||||
this.dbIdentity = config.getDatabasePlatform().getDbIdentity();
|
||||
@@ -192,7 +186,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
this.reflectFactory = createReflectionFactory();
|
||||
this.transientProperties = new TransientProperties();
|
||||
this.allowSubclassing = config.getServerConfig().isAllowSubclassing();
|
||||
}
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptorById(String descriptorId) {
|
||||
@@ -201,17 +194,11 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> entityType) {
|
||||
|
||||
// remove $$EntityBean stuff
|
||||
String className = SubClassUtil.getSuperClassName(entityType.getName());
|
||||
return (BeanDescriptor<T>) descMap.get(className);
|
||||
return (BeanDescriptor<T>) descMap.get(entityType.getName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanDescriptor<T> getBeanDescriptor(String entityClassName) {
|
||||
|
||||
// remove $$EntityBean stuff
|
||||
entityClassName = SubClassUtil.getSuperClassName(entityClassName);
|
||||
return (BeanDescriptor<T>) descMap.get(entityClassName);
|
||||
}
|
||||
|
||||
@@ -440,8 +427,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
public BeanManager<?> getBeanManager(String beanClassName) {
|
||||
|
||||
beanClassName = SubClassUtil.getSuperClassName(beanClassName);
|
||||
return beanManagerMap.get(beanClassName);
|
||||
}
|
||||
|
||||
@@ -1462,13 +1447,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
desc.setFactoryType(beanClass);
|
||||
|
||||
} else {
|
||||
if (!allowSubclassing) {
|
||||
throw new PersistenceException("This configuration does not allow entity subclassing [" + beanClass + "]");
|
||||
}
|
||||
subclassClassCount++;
|
||||
Class<?> subClass = subClassManager.resolve(beanClass.getName());
|
||||
desc.setFactoryType(subClass);
|
||||
subclassedEntities.add(desc.getName());
|
||||
throw new PersistenceException("Entity type "+beanClass+" is not an enhanced entity bean. Subclassing is not longer supported in Ebean");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -382,13 +382,12 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
if (embedded){
|
||||
throw new RuntimeException();
|
||||
} else {
|
||||
boolean vanillaMode = false;
|
||||
T ref = targetDescriptor.createReference(vanillaMode, Boolean.FALSE, cacheData, null);
|
||||
T ref = targetDescriptor.createReference(Boolean.FALSE, cacheData, null);
|
||||
setValue(bean, ref);
|
||||
if (oldValues != null){
|
||||
setValue(oldValues, ref);
|
||||
}
|
||||
if (readOnly && !vanillaMode){
|
||||
if (readOnly){
|
||||
((EntityBean)ref)._ebean_intercept().setReadOnly(true);
|
||||
}
|
||||
}
|
||||
@@ -438,11 +437,11 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
|
||||
/**
|
||||
* Create a vanilla bean of the target type to be used as an embeddedId
|
||||
* Create a bean of the target type to be used as an embeddedId
|
||||
* value.
|
||||
*/
|
||||
public Object createEmbeddedId() {
|
||||
return getTargetDescriptor().createVanillaBean();
|
||||
return getTargetDescriptor().createBean();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -736,16 +735,14 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
// parent always null for this case (but here to document)
|
||||
Object parent = null;
|
||||
boolean vanillaMode = ctx.isVanillaMode();
|
||||
//ReferenceOptions options = ctx.getReferenceOptionsFor(beanProp);
|
||||
|
||||
Boolean readOnly = ctx.isReadOnly();
|
||||
Object ref;
|
||||
if (targetInheritInfo != null) {
|
||||
// for inheritance hierarchy create the correct type for this row...
|
||||
ref = rowDescriptor.createReference(vanillaMode, readOnly, id, parent);
|
||||
ref = rowDescriptor.createReference(readOnly, id, parent);
|
||||
} else {
|
||||
ref = targetDescriptor.createReference(vanillaMode, readOnly, id, parent);
|
||||
ref = targetDescriptor.createReference(readOnly, id, parent);
|
||||
}
|
||||
|
||||
Object existingBean = ctx.getPersistenceContext().putIfAbsent(id, ref);
|
||||
@@ -755,7 +752,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
// loaded a matching bean so we will use that instead.
|
||||
ref = existingBean;
|
||||
|
||||
} else if (!vanillaMode){
|
||||
} else {
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
if (Boolean.TRUE.equals(ctx.isReadOnly())){
|
||||
ebi.setReadOnly(true);
|
||||
@@ -831,18 +828,15 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
boolean vanillaMode = ctx.isVanillaMode();
|
||||
Object parent = null;
|
||||
Object ref = targetDescriptor.createReference(vanillaMode, ctx.isReadOnly(), id, parent);
|
||||
Object ref = targetDescriptor.createReference(ctx.isReadOnly(), id, parent);
|
||||
|
||||
if (!vanillaMode){
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
if (Boolean.TRUE.equals(ctx.isReadOnly())) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
persistCtx.put(id, ref);
|
||||
ctx.register(name, ebi);
|
||||
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
|
||||
if (Boolean.TRUE.equals(ctx.isReadOnly())) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
persistCtx.put(id, ref);
|
||||
ctx.register(name, ebi);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,35 +13,25 @@ import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
*/
|
||||
public interface DbReadContext {
|
||||
|
||||
/**
|
||||
* Return the state of the object graph.
|
||||
*/
|
||||
public Boolean isReadOnly();
|
||||
/**
|
||||
* Return the state of the object graph.
|
||||
*/
|
||||
public Boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Propagate the state to the bean.
|
||||
*/
|
||||
public void propagateState(Object e);
|
||||
|
||||
/**
|
||||
* Propagate the state to the bean.
|
||||
*/
|
||||
public void propagateState(Object e);
|
||||
|
||||
/**
|
||||
* Return the DataReader.
|
||||
*/
|
||||
public DataReader getDataReader();
|
||||
|
||||
/**
|
||||
* Return true if vanilla objects should be returned.
|
||||
*/
|
||||
public boolean isVanillaMode();
|
||||
|
||||
/**
|
||||
* Return the DataReader.
|
||||
*/
|
||||
public DataReader getDataReader();
|
||||
|
||||
/**
|
||||
* Return true if the query is using supplied SQL rather than generated SQL.
|
||||
*/
|
||||
public boolean isRawSql();
|
||||
|
||||
// /**
|
||||
// * Return the reference options for a given bean property.
|
||||
// */
|
||||
// public ReferenceOptions getReferenceOptionsFor(BeanPropertyAssocOne<?> beanProperty);
|
||||
|
||||
/**
|
||||
* Set the JoinNode - used by proxy/reference beans for profiling.
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInheritInfo;
|
||||
import com.avaje.ebeaninternal.server.query.SqlTreeProperties;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassUtil;
|
||||
|
||||
/**
|
||||
* Represents a node in the Inheritance tree. Holds information regarding Super
|
||||
@@ -224,8 +223,8 @@ public class InheritInfo {
|
||||
/**
|
||||
* Create an EntityBean for this type.
|
||||
*/
|
||||
public Object createBean(boolean vanillaMode) {
|
||||
return descriptor.createBean(vanillaMode);
|
||||
public Object createBean() {
|
||||
return descriptor.createBean();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,8 +283,7 @@ public class InheritInfo {
|
||||
* Return the InheritInfo for the given bean type.
|
||||
*/
|
||||
private InheritInfo getTypeByClass(Class<?> beanType) {
|
||||
String clsName = SubClassUtil.getSuperClassName(beanType.getName());
|
||||
return typeMap.get(clsName);
|
||||
return typeMap.get(beanType.getName());
|
||||
}
|
||||
|
||||
private void registerWithRoot(InheritInfo info) {
|
||||
@@ -293,8 +291,7 @@ public class InheritInfo {
|
||||
String stringDiscValue = info.getDiscriminatorStringValue();
|
||||
discMap.put(stringDiscValue, info);
|
||||
}
|
||||
String clsName = SubClassUtil.getSuperClassName(info.getType().getName());
|
||||
typeMap.put(clsName, info);
|
||||
typeMap.put(info.getType().getName(), info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -238,7 +238,7 @@ public final class IdBinderEmbedded implements IdBinder {
|
||||
String msg = "Failed to split ["+idTermValue+"] using | for id.";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
Object embId = idDesc.createVanillaBean();
|
||||
Object embId = idDesc.createBean();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object v = props[i].getScalarType().parse(split[i]);
|
||||
props[i].setValue(embId, v);
|
||||
@@ -299,7 +299,7 @@ public final class IdBinderEmbedded implements IdBinder {
|
||||
|
||||
public Object readData(DataInput dataInput) throws IOException {
|
||||
|
||||
Object embId = idDesc.createVanillaBean();
|
||||
Object embId = idDesc.createBean();
|
||||
boolean notNull = true;
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
@@ -332,7 +332,7 @@ public final class IdBinderEmbedded implements IdBinder {
|
||||
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
|
||||
Object embId = idDesc.createVanillaBean();
|
||||
Object embId = idDesc.createBean();
|
||||
boolean notNull = true;
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
|
||||
@@ -253,8 +253,6 @@ public class PooledConnection extends ConnectionDelegator
|
||||
*/
|
||||
public void closeConnectionFully(boolean logErrors) {
|
||||
|
||||
//pool.removeConnection(this);
|
||||
|
||||
String msg = "Closing Connection[" + getName() + "]" + " psReuse[" + pstmtHitCounter
|
||||
+ "] psCreate[" + pstmtMissCounter + "] psSize[" + pstmtCache.size() + "]";
|
||||
|
||||
@@ -262,14 +260,12 @@ public class PooledConnection extends ConnectionDelegator
|
||||
|
||||
try {
|
||||
if (connection.isClosed()) {
|
||||
msg = "Closing Connection[" + getName() + "] that is already closed?";
|
||||
logger.error(msg);
|
||||
logger.warn("Closing Connection[" + getName() + "] that is already closed?");
|
||||
return;
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
if (logErrors) {
|
||||
msg = "Error when fully closing connection [" + getName() + "]";
|
||||
logger.error(msg, ex);
|
||||
logger.error("Error when fully closing connection [" + getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,11 +284,9 @@ public class PooledConnection extends ConnectionDelegator
|
||||
|
||||
try {
|
||||
connection.close();
|
||||
|
||||
} catch (SQLException ex) {
|
||||
if (logErrors) {
|
||||
msg = "Error when fully closing connection [" + getName() + "]";
|
||||
logger.error(msg, ex);
|
||||
logger.error("Error when fully closing connection [" + getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,8 +338,7 @@ public class PooledConnectionQueue {
|
||||
closeFreeConnections(true);
|
||||
|
||||
if (!busyList.isEmpty()) {
|
||||
String msg = "A potential connection leak was detected. Busy connections: "+ busyList.size();
|
||||
logger.warn(msg);
|
||||
logger.warn("A potential connection leak was detected. Busy connections: "+ busyList.size());
|
||||
|
||||
dumpBusyConnectionInformation();
|
||||
closeBusyConnections(0);
|
||||
|
||||
@@ -126,7 +126,7 @@ public class DLoadManyContext implements LoadManyContext, BeanCollectionLoader {
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
BeanDescriptor<? extends Object> parentDesc = desc.getBeanDescriptor(ownerBean.getClass());
|
||||
Object parentId = parentDesc.getId(ownerBean);
|
||||
if (parentDesc.cacheLoadMany(property, bc, parentId, parent.isReadOnly(), false)) {
|
||||
if (parentDesc.cacheLoadMany(property, bc, parentId, parent.isReadOnly())) {
|
||||
// we loaded the bean from cache
|
||||
weakList.removeEntry(position);
|
||||
return;
|
||||
|
||||
@@ -70,8 +70,8 @@ public final class DefaultPersister implements Persister {
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final boolean defaultUpdateNullProperties;
|
||||
private final boolean defaultDeleteMissingChildren;
|
||||
// private final boolean defaultUpdateNullProperties;
|
||||
// private final boolean defaultDeleteMissingChildren;
|
||||
|
||||
public DefaultPersister(SpiEbeanServer server, Binder binder, BeanDescriptorManager descMgr, PstmtBatch pstmtBatch) {
|
||||
|
||||
@@ -79,8 +79,8 @@ public final class DefaultPersister implements Persister {
|
||||
this.beanDescriptorManager = descMgr;
|
||||
this.persistExecute = new DefaultPersistExecute(binder, pstmtBatch);
|
||||
|
||||
this.defaultUpdateNullProperties = server.isDefaultUpdateNullProperties();
|
||||
this.defaultDeleteMissingChildren = server.isDefaultDeleteMissingChildren();
|
||||
// this.defaultUpdateNullProperties = server.isDefaultUpdateNullProperties();
|
||||
// this.defaultDeleteMissingChildren = server.isDefaultDeleteMissingChildren();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,8 +271,7 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
|
||||
if (bean instanceof EntityBean == false) {
|
||||
saveVanillaRecurse(bean, t, parentBean);
|
||||
return;
|
||||
throw new IllegalArgumentException("This bean is of type ["+bean.getClass()+"] is not enhanced?");
|
||||
}
|
||||
|
||||
PersistRequestBean<?> req = createRequest(bean, t, parentBean);
|
||||
@@ -313,42 +312,6 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this is an Insert or update for the 'vanilla' bean.
|
||||
*/
|
||||
private void saveVanillaRecurse(Object bean, Transaction t, Object parentBean) {
|
||||
|
||||
BeanManager<?> mgr = getBeanManager(bean);
|
||||
if (mgr == null) {
|
||||
throw new RuntimeException("No Mgr found for " + bean + " " + bean.getClass());
|
||||
}
|
||||
// use the version property to determine insert or update
|
||||
if (mgr.getBeanDescriptor().isVanillaInsert(bean)) {
|
||||
saveVanillaInsert(bean, t, parentBean, mgr);
|
||||
|
||||
} else {
|
||||
// update non-null properties (no partial object knowledge with vanilla bean)
|
||||
forceUpdateStateless(bean, t, parentBean, mgr, null, defaultDeleteMissingChildren, defaultUpdateNullProperties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform insert on non-enhanced bean (effectively same as enhanced bean).
|
||||
*/
|
||||
private void saveVanillaInsert(Object bean, Transaction t, Object parentBean, BeanManager<?> mgr) {
|
||||
|
||||
PersistRequestBean<?> req = createRequest(bean, t, parentBean, mgr);
|
||||
try {
|
||||
req.initTransIfRequired();
|
||||
insert(req);
|
||||
req.commitTransIfRequired();
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
req.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the bean.
|
||||
*/
|
||||
|
||||
@@ -72,8 +72,8 @@ public class MetaFactory {
|
||||
embeddedFact.create(allList, desc, DmlMode.WHERE, false);
|
||||
assocOneFact.create(allList, desc, DmlMode.WHERE);
|
||||
|
||||
Bindable setBindable = new BindableList(setList);
|
||||
Bindable allBindable = new BindableList(allList);
|
||||
BindableList setBindable = new BindableList(setList);
|
||||
BindableList allBindable = new BindableList(allList);
|
||||
|
||||
return new UpdateMeta(emptyStringAsNull, desc, setBindable, id, ver, allBindable);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public final class UpdateMeta {
|
||||
|
||||
private final String sqlNone;
|
||||
|
||||
private final Bindable set;
|
||||
private final BindableList set;
|
||||
private final BindableId id;
|
||||
private final Bindable version;
|
||||
private final Bindable all;
|
||||
@@ -37,7 +37,7 @@ public final class UpdateMeta {
|
||||
|
||||
private final boolean emptyStringAsNull;
|
||||
|
||||
public UpdateMeta(boolean emptyStringAsNull, BeanDescriptor<?> desc, Bindable set, BindableId id, Bindable version, Bindable all) {
|
||||
public UpdateMeta(boolean emptyStringAsNull, BeanDescriptor<?> desc, BindableList set, BindableId id, Bindable version, Bindable all) {
|
||||
this.emptyStringAsNull = emptyStringAsNull;
|
||||
this.tableName = desc.getBaseTable();
|
||||
this.set = set;
|
||||
@@ -154,7 +154,12 @@ public final class UpdateMeta {
|
||||
|
||||
// build a bindableList that only contains the changed properties
|
||||
List<Bindable> list = new ArrayList<Bindable>();
|
||||
set.addChanged(persistRequest, list);
|
||||
if (updatedProps == null) {
|
||||
// update all the properties
|
||||
set.addAll(list);
|
||||
} else {
|
||||
set.addChanged(persistRequest, list);
|
||||
}
|
||||
BindableList bindableList = new BindableList(list);
|
||||
|
||||
// build the SQL for this update statement
|
||||
|
||||
@@ -17,6 +17,12 @@ public class BindableList implements Bindable {
|
||||
items = list.toArray(new Bindable[list.size()]);
|
||||
}
|
||||
|
||||
public void addAll(List<Bindable> list) {
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
list.add(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void addChanged(PersistRequestBean<?> request, List<Bindable> list) {
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
items[i].addChanged(request, list);
|
||||
|
||||
@@ -317,13 +317,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
return queryMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we want to return vanilla (not enhanced) objects.
|
||||
*/
|
||||
public boolean isVanillaMode() {
|
||||
return request.isVanillaMode();
|
||||
}
|
||||
|
||||
public CQueryPredicates getPredicates() {
|
||||
return predicates;
|
||||
}
|
||||
@@ -586,11 +579,11 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
currentDetailCollection = manyPropertyEl.elGetValue(loadedBean);
|
||||
} else {
|
||||
// create a new collection to populate and assign to the bean
|
||||
currentDetailCollection = manyProperty.createEmpty(request.isVanillaMode());
|
||||
currentDetailCollection = manyProperty.createEmpty(false);
|
||||
manyPropertyEl.elSetValue(loadedBean, currentDetailCollection, false, false);
|
||||
}
|
||||
|
||||
if (filterMany != null && !request.isVanillaMode()) {
|
||||
if (filterMany != null) {
|
||||
// remember the for use with a refresh
|
||||
((BeanCollection<?>) currentDetailCollection).setFilterMany(filterMany);
|
||||
}
|
||||
|
||||
@@ -263,10 +263,6 @@ public class CQueryFetchIds {
|
||||
return dataReader;
|
||||
}
|
||||
|
||||
public boolean isVanillaMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Boolean isReadOnly() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
localType = null;
|
||||
localDesc = desc;
|
||||
} else {
|
||||
localBean = localInfo.createBean(ctx.isVanillaMode());
|
||||
localBean = localInfo.createBean();
|
||||
localType = localInfo.getType();
|
||||
localIdBinder = localInfo.getIdBinder();
|
||||
localDesc = localInfo.getBeanDescriptor();
|
||||
@@ -205,7 +205,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
} else {
|
||||
localType = null;
|
||||
localDesc = desc;
|
||||
localBean = desc.createBean(ctx.isVanillaMode());
|
||||
localBean = desc.createBean();
|
||||
localIdBinder = idBinder;
|
||||
}
|
||||
|
||||
@@ -295,11 +295,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
} else if (localBean != null) {
|
||||
|
||||
ctx.setCurrentPrefix(prefix, pathMap);
|
||||
if (!ctx.isVanillaMode()) {
|
||||
// only create lazy loading collection proxies
|
||||
// when not in vanilla mode
|
||||
createListProxies(localDesc, ctx, localBean);
|
||||
}
|
||||
createListProxies(localDesc, ctx, localBean);
|
||||
|
||||
localDesc.postLoad(localBean, includedProps);
|
||||
|
||||
|
||||
@@ -128,11 +128,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
private String lazyLoadProperty;
|
||||
|
||||
private String lazyLoadManyPath;
|
||||
|
||||
/**
|
||||
* Set to true when we want to return vanilla (not enhanced) objects.
|
||||
*/
|
||||
private Boolean vanillaMode;
|
||||
|
||||
/**
|
||||
* Set to true if you want a DISTINCT query.
|
||||
@@ -447,7 +442,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
copy.timeout = timeout;
|
||||
copy.mapKey = mapKey;
|
||||
copy.id = id;
|
||||
copy.vanillaMode = vanillaMode;
|
||||
copy.loadBeanCache = loadBeanCache;
|
||||
copy.useBeanCache = useBeanCache;
|
||||
copy.useQueryCache = useQueryCache;
|
||||
@@ -776,20 +770,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return maxRows > 0 || firstRow > 0;
|
||||
}
|
||||
|
||||
|
||||
public boolean isVanillaMode(boolean defaultVanillaMode) {
|
||||
if (vanillaMode != null) {
|
||||
return vanillaMode.booleanValue();
|
||||
}
|
||||
return defaultVanillaMode;
|
||||
}
|
||||
|
||||
public DefaultOrmQuery<T> setVanillaMode(boolean vanillaMode) {
|
||||
this.vanillaMode = vanillaMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean isReadOnly() {
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
/**
|
||||
* The suffix used build a generated EntityBean class.
|
||||
* <p>
|
||||
* Note that the server name can be appended after
|
||||
* </p>
|
||||
*/
|
||||
public interface GenSuffix {
|
||||
|
||||
/**
|
||||
* The suffix added to the super class name.
|
||||
*/
|
||||
public static final String SUFFIX = "$$EntityBean";
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.enhance.agent.ClassMeta;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceConstants;
|
||||
import com.avaje.ebean.enhance.agent.FieldMeta;
|
||||
import com.avaje.ebean.enhance.asm.ClassVisitor;
|
||||
import com.avaje.ebean.enhance.asm.Opcodes;
|
||||
|
||||
public class GetterSetterMethods implements Opcodes, EnhanceConstants {
|
||||
|
||||
/**
|
||||
* Add getters and setters to for interception.
|
||||
* <p>
|
||||
* Note that we don't intercept Id properties and we don't intercept setters
|
||||
* on 'OneToMany' properties etc.
|
||||
* </p>
|
||||
*/
|
||||
public static void add(ClassVisitor cv, ClassMeta classMeta) {
|
||||
|
||||
List<FieldMeta> localFields = classMeta.getLocalFields();
|
||||
for (int x = 0; x < localFields.size(); x++) {
|
||||
FieldMeta fieldMeta = localFields.get(x);
|
||||
fieldMeta.addPublicGetSetMethods(cv, classMeta, true);
|
||||
}
|
||||
|
||||
List<FieldMeta> inheritedFields = classMeta.getInheritedFields();
|
||||
for (int i = 0; i < inheritedFields.size(); i++) {
|
||||
FieldMeta fieldMeta = inheritedFields.get(i);
|
||||
// for persistent inherited fields add a
|
||||
// getter and setter to enable interception
|
||||
fieldMeta.addPublicGetSetMethods(cv, classMeta, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
import com.avaje.ebean.enhance.agent.ClassMeta;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceConstants;
|
||||
import com.avaje.ebean.enhance.asm.ClassVisitor;
|
||||
import com.avaje.ebean.enhance.asm.Label;
|
||||
import com.avaje.ebean.enhance.asm.MethodVisitor;
|
||||
import com.avaje.ebean.enhance.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* Add a writeReplace method to support optional serialization to vanilla beans.
|
||||
*
|
||||
* <pre><code>
|
||||
* private Object writeReplace() throws ObjectStreamException {
|
||||
* return ebeanIntercept.writeReplaceIntercept();
|
||||
* }
|
||||
* </code></pre>
|
||||
*/
|
||||
public class MethodWriteReplace implements Opcodes, EnhanceConstants {
|
||||
|
||||
/**
|
||||
* Add a writeReplace() method.
|
||||
*/
|
||||
public static void add(ClassVisitor cv, ClassMeta classMeta) {
|
||||
|
||||
MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "writeReplace", "()Ljava/lang/Object;",
|
||||
null, new String[] { "java/io/ObjectStreamException" });
|
||||
|
||||
mv.visitCode();
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitLineNumber(1, l0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, classMeta.getClassName(), INTERCEPT_FIELD, L_INTERCEPT);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, C_INTERCEPT, "writeReplaceIntercept","()Ljava/lang/Object;");
|
||||
|
||||
mv.visitInsn(ARETURN);
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitLocalVariable("this", "L"+classMeta.getClassName()+";", null, l0, l1, 0);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
import com.avaje.ebean.enhance.agent.AlreadyEnhancedException;
|
||||
import com.avaje.ebean.enhance.agent.ClassMeta;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceConstants;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceContext;
|
||||
import com.avaje.ebean.enhance.agent.IndexFieldWeaver;
|
||||
import com.avaje.ebean.enhance.agent.InterceptField;
|
||||
import com.avaje.ebean.enhance.agent.MarkerField;
|
||||
import com.avaje.ebean.enhance.agent.MethodEquals;
|
||||
import com.avaje.ebean.enhance.agent.MethodIsEmbeddedNewOrDirty;
|
||||
import com.avaje.ebean.enhance.agent.MethodNewInstance;
|
||||
import com.avaje.ebean.enhance.agent.MethodPropertyChangeListener;
|
||||
import com.avaje.ebean.enhance.agent.MethodSetEmbeddedLoaded;
|
||||
import com.avaje.ebean.enhance.agent.NoEnhancementRequiredException;
|
||||
import com.avaje.ebean.enhance.agent.VisitMethodParams;
|
||||
import com.avaje.ebean.enhance.asm.AnnotationVisitor;
|
||||
import com.avaje.ebean.enhance.asm.ClassAdapter;
|
||||
import com.avaje.ebean.enhance.asm.ClassVisitor;
|
||||
import com.avaje.ebean.enhance.asm.FieldVisitor;
|
||||
import com.avaje.ebean.enhance.asm.MethodVisitor;
|
||||
import com.avaje.ebean.enhance.asm.Opcodes;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SubClassClassAdpater extends ClassAdapter implements EnhanceConstants {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SubClassClassAdpater.class);
|
||||
|
||||
final EnhanceContext enhanceContext;
|
||||
|
||||
final ClassLoader classLoader;
|
||||
|
||||
final ClassMeta classMeta;
|
||||
|
||||
final String subClassSuffix;
|
||||
|
||||
boolean firstMethod = true;
|
||||
|
||||
public SubClassClassAdpater(String subClassSuffix, ClassVisitor cv, ClassLoader classLoader, EnhanceContext context) {
|
||||
super(cv);
|
||||
this.subClassSuffix = subClassSuffix;
|
||||
this.classLoader = classLoader;
|
||||
this.enhanceContext = context;
|
||||
this.classMeta = context.createClassMeta();
|
||||
}
|
||||
|
||||
public boolean isLog(int level){
|
||||
return classMeta.isLog(level);
|
||||
}
|
||||
|
||||
public void log(String msg){
|
||||
classMeta.log(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the class definition replacing the className and super class.
|
||||
*/
|
||||
public void visit(int version, int access, String name, String signature, String superName,
|
||||
String[] interfaces) {
|
||||
|
||||
// Note: interfaces can be an empty array but not null
|
||||
int n = 1 + interfaces.length;
|
||||
String[] c = new String[n];
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
c[i] = interfaces[i];
|
||||
if (c[i].equals(C_ENTITYBEAN)) {
|
||||
throw new AlreadyEnhancedException(name);
|
||||
}
|
||||
if (c[i].equals(C_SCALAOBJECT)) {
|
||||
classMeta.setScalaInterface(true);
|
||||
}
|
||||
if (c[i].equals(C_GROOVYOBJECT)) {
|
||||
classMeta.setGroovyInterface(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the EntityBean interface
|
||||
c[c.length - 1] = C_ENTITYBEAN;
|
||||
|
||||
if (!superName.equals("java/lang/Object")){
|
||||
|
||||
ClassMeta superMeta = enhanceContext.getSuperMeta(superName, classLoader);
|
||||
if (superMeta != null) {
|
||||
classMeta.setSuperMeta(superMeta);
|
||||
if (classMeta.isLog(2)){
|
||||
classMeta.log("entity inheritance "+superMeta.getDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjust the superName and name as we
|
||||
// are actually creating a subclass of
|
||||
// the class being visited
|
||||
superName = name;
|
||||
name = name+subClassSuffix;
|
||||
|
||||
classMeta.setClassName(name, superName);
|
||||
|
||||
super.visit(version, access, name, signature, superName, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
classMeta.addClassAnnotation(desc);
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ebeanIntercept field is added once but thats all. Note the other
|
||||
* fields are defined in the superclass.
|
||||
*/
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature,
|
||||
Object value) {
|
||||
|
||||
if ((access & Opcodes.ACC_STATIC) != 0) {
|
||||
// no interception of static fields
|
||||
if (isLog(2)){
|
||||
log("Skip intercepting static field "+name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & Opcodes.ACC_TRANSIENT) != 0) {
|
||||
// no interception of transient fields
|
||||
if (classMeta.isLog(2)){
|
||||
classMeta.log("Skip intercepting transient field "+name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// read the field and associated annotations...
|
||||
if (classMeta.isLog(5)){
|
||||
classMeta.log(" ... reading field:"+name+" desc:"+desc);
|
||||
}
|
||||
|
||||
return classMeta.createLocalFieldVisitor(name, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the method code with calls to super. Add the intercept code as
|
||||
* required.
|
||||
*/
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
||||
String[] exceptions) {
|
||||
|
||||
if (firstMethod){
|
||||
if (!classMeta.isEntityEnhancementRequired()) {
|
||||
// skip the rest of the visiting etc
|
||||
throw new NoEnhancementRequiredException();
|
||||
}
|
||||
|
||||
// always add the marker field on every enhanced class
|
||||
String marker = MarkerField.addField(cv, classMeta.getClassName());
|
||||
if (isLog(4)){
|
||||
log("... add marker field \""+marker+"\"");
|
||||
log("... add intercept and identity fields");
|
||||
}
|
||||
|
||||
// always add these fields for subclass generation
|
||||
InterceptField.addField(cv, enhanceContext.isTransientInternalFields());
|
||||
MethodEquals.addIdentityField(cv);
|
||||
firstMethod = false;
|
||||
}
|
||||
|
||||
|
||||
VisitMethodParams params = new VisitMethodParams(cv, access, name, desc, signature, exceptions);
|
||||
|
||||
if (isDefaultConstructor(access, name, desc, signature, exceptions)){
|
||||
SubClassConstructor.add(params, classMeta);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isSpecialMethod(access, name, desc)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// register the method so that we can check
|
||||
// if it exists when GetterSetterMethods.add()
|
||||
// is called. May not exist on read only type
|
||||
// entity beans such as the internal meta beans.
|
||||
classMeta.addExistingSuperMethod(name, desc);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add methods to get and set the entityBeanIntercept. Also add the
|
||||
* writeReplace method to control serialisation.
|
||||
*/
|
||||
public void visitEnd() {
|
||||
|
||||
if (!classMeta.isEntityEnhancementRequired()){
|
||||
throw new NoEnhancementRequiredException();
|
||||
}
|
||||
|
||||
if (!classMeta.hasDefaultConstructor()){
|
||||
if (isLog(2)){
|
||||
log("... adding default constructor");
|
||||
}
|
||||
SubClassConstructor.addDefault(cv, classMeta);
|
||||
}
|
||||
|
||||
MarkerField.addGetMarker(cv, classMeta.getClassName());
|
||||
|
||||
// Add the _ebean_getIntercept() _ebean_setIntercept() methods
|
||||
InterceptField.addGetterSetter(cv, classMeta.getClassName());
|
||||
|
||||
// Add add/removePropertyChangeListener methods
|
||||
MethodPropertyChangeListener.addMethod(cv, classMeta);
|
||||
|
||||
// Add getter and setter methods for both local
|
||||
// and inherited properties
|
||||
GetterSetterMethods.add(cv, classMeta);
|
||||
|
||||
// Add extra methods such as getField(index) etc
|
||||
IndexFieldWeaver.addMethods(cv, classMeta);
|
||||
|
||||
MethodSetEmbeddedLoaded.addMethod(cv, classMeta);
|
||||
MethodIsEmbeddedNewOrDirty.addMethod(cv, classMeta);
|
||||
MethodNewInstance.addMethod(cv, classMeta);
|
||||
|
||||
// add a writeReplace method to control serialisation
|
||||
MethodWriteReplace.add(cv, classMeta);
|
||||
|
||||
// register with the context
|
||||
enhanceContext.addClassMeta(classMeta);
|
||||
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is the default (no arg) constructor.
|
||||
*/
|
||||
private boolean isDefaultConstructor(int access, String name, String desc, String signature,
|
||||
String[] exceptions){
|
||||
|
||||
if (name.equals("<init>") && desc.equals("()V")) {
|
||||
classMeta.setHasDefaultConstructor(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take note of hashcode and equals.
|
||||
*/
|
||||
private boolean isSpecialMethod(int access, String name, String desc) {
|
||||
|
||||
if (name.equals("hashCode") && desc.equals("()I")) {
|
||||
classMeta.setHasEqualsOrHashcode(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name.equals("equals") && desc.equals("(Ljava/lang/Object;)Z")) {
|
||||
classMeta.setHasEqualsOrHashcode(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
import com.avaje.ebean.enhance.agent.ClassMeta;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceConstants;
|
||||
import com.avaje.ebean.enhance.agent.VisitMethodParams;
|
||||
import com.avaje.ebean.enhance.asm.ClassVisitor;
|
||||
import com.avaje.ebean.enhance.asm.Label;
|
||||
import com.avaje.ebean.enhance.asm.MethodVisitor;
|
||||
import com.avaje.ebean.enhance.asm.Opcodes;
|
||||
|
||||
public class SubClassConstructor implements Opcodes, EnhanceConstants{
|
||||
|
||||
public static void addDefault(ClassVisitor cv, ClassMeta meta) {
|
||||
VisitMethodParams params = new VisitMethodParams(cv, Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
add(params, meta);
|
||||
}
|
||||
|
||||
public static void add(VisitMethodParams params, ClassMeta meta) {
|
||||
|
||||
String className = meta.getClassName();
|
||||
String superClassName = meta.getSuperClassName();
|
||||
|
||||
if (params.forcePublic()){
|
||||
if (meta.isLog(0)){
|
||||
meta.log(" forcing ACC_PUBLIC ");
|
||||
}
|
||||
}
|
||||
|
||||
MethodVisitor mv = params.visitMethod();
|
||||
//mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitLineNumber(17, l0);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, superClassName, "<init>", "()V");
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitLineNumber(18, l1);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitTypeInsn(NEW, C_INTERCEPT);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, C_INTERCEPT, "<init>", "(Ljava/lang/Object;)V");
|
||||
mv.visitFieldInsn(PUTFIELD, className, INTERCEPT_FIELD, L_INTERCEPT);
|
||||
Label l2 = new Label();
|
||||
mv.visitLabel(l2);
|
||||
mv.visitLineNumber(19, l2);
|
||||
mv.visitInsn(RETURN);
|
||||
Label l3 = new Label();
|
||||
mv.visitLabel(l3);
|
||||
mv.visitLocalVariable("this", "L"+className+";", null, l0, l3, 0);
|
||||
mv.visitMaxs(4, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.avaje.ebean.enhance.agent.ClassPathClassBytesReader;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceConstants;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceContext;
|
||||
import com.avaje.ebean.enhance.asm.ClassReader;
|
||||
import com.avaje.ebean.enhance.asm.ClassWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Creates Classes that implement EntityBean for a given normal bean Class.
|
||||
* <p>
|
||||
* This dynamically creates a subclass of a normal bean class. The subclass has
|
||||
* method interception to handle the lazy loading of references and old values
|
||||
* creation.
|
||||
* </p>
|
||||
*/
|
||||
public class SubClassFactory extends ClassLoader implements EnhanceConstants, GenSuffix {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SubClassFactory.class);
|
||||
|
||||
private static final int CLASS_WRITER_FLAGS = ClassWriter.COMPUTE_FRAMES + ClassWriter.COMPUTE_MAXS;
|
||||
|
||||
private final EnhanceContext enhanceContext;
|
||||
|
||||
private final ClassLoader parentClassLoader;
|
||||
|
||||
|
||||
/**
|
||||
* Create with a given ClassLoader.
|
||||
*/
|
||||
public SubClassFactory(ClassLoader parent, int logLevel) {
|
||||
super(parent);
|
||||
parentClassLoader = parent;
|
||||
|
||||
ClassPathClassBytesReader reader = new ClassPathClassBytesReader(null);
|
||||
enhanceContext = new EnhanceContext(reader, true, "debug="+logLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a subclass for the given bean class that implements EntityBean interface.
|
||||
* <p>
|
||||
* The transientGetters is a list of getter methods that are considered
|
||||
* no persistent. That is, when they are called the bean should NOT
|
||||
* trigger creation of an 'old values' copy of the beans values.
|
||||
* </p>
|
||||
*/
|
||||
public Class<?> create(Class<?> normalClass, String serverName) throws IOException {
|
||||
|
||||
String subClassSuffix = EnhanceConstants.SUFFIX;
|
||||
if (serverName != null){
|
||||
subClassSuffix += "$"+serverName;
|
||||
}
|
||||
|
||||
// Note: these have periods rather than slashes
|
||||
String clsName = normalClass.getName();
|
||||
String subClsName = clsName+subClassSuffix;
|
||||
|
||||
try {
|
||||
byte[] newClsBytes = subclassBytes(clsName, subClassSuffix);
|
||||
|
||||
Class<?> newCls = defineClass(subClsName, newClsBytes, 0, newClsBytes.length);
|
||||
return newCls;
|
||||
|
||||
} catch (IOException ex){
|
||||
String m = "Error creating subclass for ["+clsName+"]";
|
||||
logger.error(m, ex);
|
||||
throw ex;
|
||||
|
||||
} catch (Throwable ex){
|
||||
String m = "Error creating subclass for ["+clsName+"]";
|
||||
logger.error(m, ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return byte code for the subclass.
|
||||
* <p>
|
||||
* Note that if transientInfo is null, then no interception of getters or setters
|
||||
* takes place.
|
||||
* </p>
|
||||
*/
|
||||
private byte[] subclassBytes(String className, String subClassSuffix)
|
||||
throws IOException {
|
||||
|
||||
String resName = className.replace('.', '/')+".class";
|
||||
|
||||
InputStream is = getResourceAsStream(resName);
|
||||
|
||||
ClassReader cr = new ClassReader(is);
|
||||
ClassWriter cw = new ClassWriter(CLASS_WRITER_FLAGS);
|
||||
|
||||
SubClassClassAdpater ca = new SubClassClassAdpater(subClassSuffix, cw, parentClassLoader, enhanceContext);
|
||||
if (ca.isLog(1)) {
|
||||
ca.log(" enhancing " + className+subClassSuffix);
|
||||
}
|
||||
|
||||
cr.accept(ca, 0);
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
|
||||
/**
|
||||
* Used to generate a subclass based on a bean.
|
||||
* <p>
|
||||
* It does not have the fields or private methods of the read class. It replaces
|
||||
* the method code with calls to super instead. It may need to add hashCode()
|
||||
* and equals() methods to make sure a reference is loaded prior to either of
|
||||
* these methods being called. It uses writeReplace() to modify the
|
||||
* serialisation.
|
||||
* </p>
|
||||
*/
|
||||
public class SubClassGenerator {// extends ClassAdapter implements Opcodes, GenConstants {
|
||||
|
||||
// private static final Logger logger = LogFactory.get(SubClassGenerator.class);
|
||||
//
|
||||
// boolean isInterceptFieldAdded = false;
|
||||
//
|
||||
// boolean isAddClonable = true;
|
||||
//
|
||||
// boolean superHasEquals = false;
|
||||
//
|
||||
// ClassInfo info;
|
||||
//
|
||||
// MethodInfo methodInfo;
|
||||
//
|
||||
// boolean hasSuperClass;
|
||||
//
|
||||
// /**
|
||||
// * Create with the ClassInfo.
|
||||
// */
|
||||
// public SubClassGenerator(ClassVisitor cv, ClassInfo info) {
|
||||
// super(cv);
|
||||
// this.info = info;
|
||||
// this.methodInfo = info.getMethodInfo();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Create the class definition replacing the className and super class.
|
||||
// */
|
||||
// public void visit(int version, int access, String name, String signature, String superName,
|
||||
// String[] interfaces) {
|
||||
//
|
||||
// // Note: These have slashes rather than periods!!
|
||||
// String className = name+info.getSuffix();
|
||||
// String superClassName;
|
||||
// if ("java/lang/Object".endsWith(superName)){
|
||||
// superClassName = name;
|
||||
// } else {
|
||||
// hasSuperClass = true;
|
||||
// superClassName = name;//superName+info.getSuffix();
|
||||
// }
|
||||
//
|
||||
// info.setClassName(className);
|
||||
// info.setSuperClassName(superClassName);
|
||||
//
|
||||
//
|
||||
// // Note: interfaces can be an empty array but not null
|
||||
// int n = 1 + interfaces.length;
|
||||
// String[] c = new String[n];
|
||||
// System.arraycopy(interfaces, 0, c, 0, interfaces.length);
|
||||
//
|
||||
// // Add the EntityBean interface
|
||||
// c[c.length - 1] = ENTITYBEAN;
|
||||
//
|
||||
// super.visit(version, access, className, signature, superClassName, c);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * The ebeanIntercept field is added once but thats all. Note the other
|
||||
// * fields are defined in the superclass.
|
||||
// */
|
||||
// public FieldVisitor visitField(int access, String name, String desc, String signature,
|
||||
// Object value) {
|
||||
//
|
||||
// if (!isInterceptFieldAdded) {
|
||||
//
|
||||
// FieldVisitor f0 = cv.visitField(ACC_PRIVATE + ACC_VOLATILE, IDENTITY_FIELD_NAME, "Ljava/lang/Object;", null, null);
|
||||
// f0.visitEnd();
|
||||
//
|
||||
// FieldVisitor f1 = cv.visitField(0, INTERCEPT_FIELD_NAME, L_INTERCEPT, null, null);
|
||||
// f1.visitEnd();
|
||||
//
|
||||
// isInterceptFieldAdded = true;
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Replace the method code with calls to super. Add the intercept code as
|
||||
// * required.
|
||||
// */
|
||||
// public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
||||
// String[] exceptions) {
|
||||
//
|
||||
// boolean isPrivate = ((access & Opcodes.ACC_PRIVATE) != 0);
|
||||
// boolean isStatic = ((access & Opcodes.ACC_STATIC) != 0);
|
||||
// if (isPrivate || isStatic) {
|
||||
// // no intercept on static or private methods
|
||||
// return null;
|
||||
// }
|
||||
// // the key to look up in methodInfo
|
||||
// String methodKey = name + ":" + desc;
|
||||
//
|
||||
// if (hasSuperClass){
|
||||
// if (logger.isTraceEnabled()){
|
||||
// String msg = "existing methods "+info.getClassName()+" "+methodKey;
|
||||
// logger.trace(msg);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// VisitMethodParams params = new VisitMethodParams(cv, access, name, desc, signature, exceptions);
|
||||
//
|
||||
// if (methodInfo.isSet(methodKey)) {
|
||||
// // for persistent properties excluding assoc Many's & id
|
||||
// // ie. Old values not created for id or assoc many.
|
||||
// return new ProxySetterMethod(params, info, methodInfo);
|
||||
// }
|
||||
//
|
||||
// if (methodInfo.isGet(methodKey)) {
|
||||
// // for persistent properties excluding id properties.
|
||||
// // ie. reference loading not fired for id properties.
|
||||
// return new ProxyGetterMethod(params, info);
|
||||
// }
|
||||
//
|
||||
// if ("<init>".equals(name)) {
|
||||
// return new ProxyConstructor(params, info);
|
||||
// }
|
||||
//
|
||||
// if ("hashCode:()I".equals(methodKey)) {
|
||||
// return new ProxyMethod(params, info);
|
||||
// }
|
||||
//
|
||||
// if ("clone:()Ljava/lang/Object;".equals(methodKey)) {
|
||||
// // SuperClass has a clone() method
|
||||
// isAddClonable = false;
|
||||
// return new MethodClone(params, info);
|
||||
// }
|
||||
//
|
||||
// if ("toString:()Ljava/lang/String;".equals(methodKey)) {
|
||||
// // No intercept on toString() as used by debuggers etc
|
||||
// return null;
|
||||
// }
|
||||
// if ("hashCode:()I".equals(methodKey)) {
|
||||
// return null;
|
||||
// }
|
||||
// if ("equals:(Ljava/lang/Object;)Z".equals(methodKey)) {
|
||||
// superHasEquals = true;
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Add methods to get and set the entityBeanIntercept. Also add the
|
||||
// * writeReplace method to control serialisation.
|
||||
// */
|
||||
// public void visitEnd() {
|
||||
//
|
||||
// if (isAddClonable){
|
||||
// // super has not overwritten the clone() method.
|
||||
// // we will add the clone() method in case a super of the super has clone()
|
||||
// String[] exceptions = new String[] { "java/lang/CloneNotSupportedException" };
|
||||
// VisitMethodParams params = new VisitMethodParams(cv, ACC_PUBLIC, "clone", "()Ljava/lang/Object;", null, exceptions);
|
||||
// MethodClone methodClone = new MethodClone(params, info);
|
||||
// methodClone.visitCode();
|
||||
// }
|
||||
//
|
||||
// MethodInfo methodInfo = info.getMethodInfo();
|
||||
// if (methodInfo.isEmbedded()){
|
||||
// // don't override equals etc when it is an embedded bean
|
||||
// // Either EmbeddedId or a Embeddable
|
||||
//
|
||||
// } else if (methodInfo.overrideEquals(superHasEquals)) {
|
||||
// // we want to generate a equals() hashCode() and ebeanGetIndentity()
|
||||
// // methods so that the generated subclass has built in equals() support.
|
||||
//
|
||||
// if (methodInfo.getIdGetter() == null) {
|
||||
// if (methodInfo.isSqlSelectBased()){
|
||||
// // This could be common for reporting type beans based on
|
||||
// // sql-select that use group by type queries.
|
||||
// } else {
|
||||
// String m = "Can not generate equals for ["+info.getClassName();
|
||||
// m += "]. Concatinated id?";
|
||||
// logger.warn(m);
|
||||
// }
|
||||
// } else {
|
||||
//
|
||||
// if (generateEbeanGetIdentityMethod()){
|
||||
// // add equals()
|
||||
// MethodEquals.add(cv, info);
|
||||
//
|
||||
// // add hashCode()
|
||||
// MethodHashCode.add(cv, info);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // add additional getters from super class inheritance
|
||||
// List<MethodDesc> additionalGetters = methodInfo.getAdditionalGetters();
|
||||
// for (MethodDesc methodDesc : additionalGetters) {
|
||||
// VisitMethodParams params = new VisitMethodParams(cv, ACC_PUBLIC, methodDesc);
|
||||
// ProxyGetterMethod getter = new ProxyGetterMethod(params, info);
|
||||
// getter.visitCode();
|
||||
// }
|
||||
//
|
||||
// // add additional setters from super class inheritance
|
||||
// List<MethodDesc> additionalSetters = methodInfo.getAdditionalSetters();
|
||||
// for (MethodDesc methodDesc : additionalSetters) {
|
||||
// VisitMethodParams params = new VisitMethodParams(cv, ACC_PUBLIC, methodDesc);
|
||||
// ProxySetterMethod setter = new ProxySetterMethod(params, info, methodInfo);
|
||||
// setter.visitCode();
|
||||
// }
|
||||
//
|
||||
// // add set get methods for ebeanIntecept
|
||||
// MethodGetSetIntercept.add(cv, info);
|
||||
//
|
||||
// // add a writeReplace method to control serialisation
|
||||
// MethodWriteReplace.add(cv, info);
|
||||
//
|
||||
// super.visitEnd();
|
||||
// }
|
||||
//
|
||||
// private boolean generateEbeanGetIdentityMethod() {
|
||||
// String idGetterDesc = methodInfo.getIdGetterDesc();
|
||||
// if (idGetterDesc.equals("()I")) {
|
||||
// // int version of ebeanGetIndentity()
|
||||
// MethodEbeanGetIdentityInt.add(cv, info);
|
||||
// return true;
|
||||
//
|
||||
// } else if (idGetterDesc.equals("()J")) {
|
||||
// // long version of ebeanGetIndentity()
|
||||
// MethodEbeanGetIdentityLong.add(cv, info);
|
||||
// return true;
|
||||
//
|
||||
// } else if (idGetterDesc.length() > 5) {
|
||||
// // Object version of ebeanGetIndentity()
|
||||
// MethodEbeanGetIdentity.add(cv, info);
|
||||
// return true;
|
||||
//
|
||||
// } else {
|
||||
// String m = "Can not generate equals for ["+info.getClassName();
|
||||
// m += "] due to type of id property: "+idGetterDesc;
|
||||
// logger.warn(m);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.enhance.agent.EnhanceConstants;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Creates and caches the dynamically generated subclasses.
|
||||
* <p>
|
||||
* That is, the 'EntityBean' classes are dynamically generated subclasses of the
|
||||
* 'vanilla' classes.
|
||||
* </p>
|
||||
*/
|
||||
public class SubClassManager implements EnhanceConstants {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SubClassManager.class);
|
||||
|
||||
private final ConcurrentHashMap<String,Class<?>> clzMap;
|
||||
|
||||
private final SubClassFactory subclassFactory;
|
||||
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* The log level for debugging subclass generation/enhancement.
|
||||
*/
|
||||
private final int logLevel;
|
||||
|
||||
/**
|
||||
* Construct with the ClassLoader used to load Ebean.class.
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public SubClassManager(ServerConfig serverConfig) {
|
||||
|
||||
String s = serverConfig.getProperty("subClassManager.preferContextClassloader", "true");
|
||||
final boolean preferContext = "true".equalsIgnoreCase(s);
|
||||
|
||||
this.serverName = serverConfig.getName();
|
||||
this.logLevel = serverConfig.getEnhanceLogLevel();
|
||||
this.clzMap = new ConcurrentHashMap<String, Class<?>>();
|
||||
|
||||
try {
|
||||
subclassFactory = (SubClassFactory) AccessController
|
||||
.doPrivileged(new PrivilegedExceptionAction() {
|
||||
public Object run() {
|
||||
ClassLoader cl = ClassUtil.getClassLoader(this.getClass(), preferContext);
|
||||
logger.info("SubClassFactory parent ClassLoader ["+cl.getClass().getName()+"]");
|
||||
return new SubClassFactory(cl, logLevel);
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the Class for the class name.
|
||||
* <p>
|
||||
* The methodInfo is used to determine the method interception on the
|
||||
* generated class.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the class has already been generated then it is returned out of a
|
||||
* cache.
|
||||
* </p>
|
||||
*/
|
||||
public Class<?> resolve(String name) {
|
||||
|
||||
synchronized (this) {
|
||||
String superName = SubClassUtil.getSuperClassName(name);
|
||||
Class<?> clz = clzMap.get(superName);
|
||||
if (clz == null) {
|
||||
clz = createClass(superName);
|
||||
clzMap.put(superName, clz);
|
||||
}
|
||||
return clz;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> createClass(String name) {
|
||||
|
||||
try {
|
||||
|
||||
Class<?> superClass = Class.forName(name, true, subclassFactory.getParent());
|
||||
|
||||
return subclassFactory.create(superClass, serverName);
|
||||
|
||||
} catch (Exception ex) {
|
||||
String m = "Error creating subclass for [" + name + "]";
|
||||
throw new PersistenceException(m, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.subclass;
|
||||
|
||||
|
||||
/**
|
||||
* Helper methods for generated sub classes.
|
||||
*/
|
||||
public class SubClassUtil implements GenSuffix {
|
||||
|
||||
/**
|
||||
* Return true if this is a generated class.
|
||||
*/
|
||||
public static boolean isSubClass(String className) {
|
||||
|
||||
return (className.lastIndexOf(SUFFIX) != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the super class name given the generated className.
|
||||
*/
|
||||
public static String getSuperClassName(String className){
|
||||
int dPos = className.lastIndexOf(SUFFIX);
|
||||
if (dPos > -1){
|
||||
return className.substring(0, dPos);
|
||||
}
|
||||
return className;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Used to generate subclasses rather than weaving</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Used to generate subclasses rather than weaving
|
||||
<p>
|
||||
As alternative to weaving/enhancing the classes via javaagent or ant you
|
||||
can use dynamically generated subclasses. These objects support that feature.
|
||||
</p>
|
||||
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
+1
-4
@@ -7,7 +7,6 @@ import java.util.Map.Entry;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.Monitor;
|
||||
import com.avaje.ebeaninternal.server.subclass.SubClassUtil;
|
||||
|
||||
/**
|
||||
* Default implementation of PersistenceContext.
|
||||
@@ -120,9 +119,7 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
|
||||
private ClassContext getClassContext(Class<?> beanType) {
|
||||
|
||||
// strip off $$EntityBean.. suffix...
|
||||
String clsName = SubClassUtil.getSuperClassName(beanType.getName());
|
||||
|
||||
String clsName = beanType.getName();
|
||||
ClassContext classMap = typeCache.get(clsName);
|
||||
if (classMap == null) {
|
||||
classMap = new ClassContext();
|
||||
|
||||
@@ -294,6 +294,10 @@ public class TransactionManager {
|
||||
c.setTransactionIsolation(isolationLevel);
|
||||
}
|
||||
|
||||
if (explicit && TXN_LOGGER.isTraceEnabled()) {
|
||||
TXN_LOGGER.trace(t.getLogPrefix()+"Begin");
|
||||
}
|
||||
|
||||
return t;
|
||||
|
||||
} catch (SQLException ex) {
|
||||
@@ -371,6 +375,9 @@ public class TransactionManager {
|
||||
public void notifyOfQueryOnly(boolean onCommit, SpiTransaction transaction, Throwable cause) {
|
||||
|
||||
// Nothing that interesting here
|
||||
if (TXN_LOGGER.isTraceEnabled()) {
|
||||
TXN_LOGGER.trace(transaction.getLogPrefix()+"Commit - query only");
|
||||
}
|
||||
}
|
||||
|
||||
private String formatThrowable(Throwable e){
|
||||
|
||||
Reference in New Issue
Block a user