Merge pull request #2626 from ebean-orm/wip/EntityBeanIntercept-interface

Support EntityBeanIntercept as an interface with InterceptReadWrite and InterceptReadOnly options
This commit is contained in:
Rob Bygrave
2022-05-03 14:15:49 +12:00
committed by GitHub
27 changed files with 1875 additions and 941 deletions
@@ -34,6 +34,13 @@ public interface EntityBean extends Serializable, ToStringAware {
throw new NotEnhancedException();
}
/**
* Create and return a new entity bean instance optimised for read only no interception use.
*/
default Object _ebean_newInstanceReadOnly() {
throw new NotEnhancedException();
}
/**
* Generated method that sets the loaded state on all the embedded beans on
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,536 @@
package io.ebean.bean;
import io.ebean.ValuePair;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
public class InterceptReadOnly implements EntityBeanIntercept {
private final EntityBean owner;
public InterceptReadOnly(Object ownerBean) {
this.owner = (EntityBean) ownerBean;
}
@Override
public EntityBean getOwner() {
return owner;
}
@Override
public PersistenceContext getPersistenceContext() {
return null;
}
@Override
public void setPersistenceContext(PersistenceContext persistenceContext) {
}
@Override
public void setNodeUsageCollector(NodeUsageCollector usageCollector) {
}
@Override
public Object getOwnerId() {
return null;
}
@Override
public void setOwnerId(Object ownerId) {
}
@Override
public Object getEmbeddedOwner() {
return null;
}
@Override
public int getEmbeddedOwnerIndex() {
return 0;
}
@Override
public void clearGetterCallback() {
}
@Override
public void registerGetterCallback(PreGetterCallback getterCallback) {
}
@Override
public void setEmbeddedOwner(EntityBean parentBean, int embeddedOwnerIndex) {
}
@Override
public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) {
}
@Override
public void setBeanLoader(BeanLoader beanLoader) {
}
@Override
public boolean isFullyLoadedBean() {
return false;
}
@Override
public void setFullyLoadedBean(boolean fullyLoadedBean) {
}
@Override
public boolean isPartial() {
return false;
}
@Override
public boolean isDirty() {
return false;
}
@Override
public void setEmbeddedDirty(int embeddedProperty) {
}
@Override
public void setDirty(boolean dirty) {
}
@Override
public boolean isNew() {
return false;
}
@Override
public boolean isNewOrDirty() {
return false;
}
@Override
public boolean hasIdOnly(int idIndex) {
return false;
}
@Override
public boolean isReference() {
return false;
}
@Override
public void setReference(int idPos) {
}
@Override
public void setLoadedFromCache(boolean loadedFromCache) {
}
@Override
public boolean isLoadedFromCache() {
return false;
}
@Override
public boolean isReadOnly() {
return true;
}
@Override
public void setReadOnly(boolean readOnly) {
}
@Override
public void setForceUpdate(boolean forceUpdate) {
}
@Override
public boolean isUpdate() {
return false;
}
@Override
public boolean isLoaded() {
return true;
}
@Override
public void setNew() {
}
@Override
public void setLoaded() {
}
@Override
public void setLoadedLazy() {
}
@Override
public void setLazyLoadFailure(Object ownerId) {
}
@Override
public boolean isLazyLoadFailure() {
return false;
}
@Override
public boolean isDisableLazyLoad() {
return false;
}
@Override
public void setDisableLazyLoad(boolean disableLazyLoad) {
}
@Override
public void setEmbeddedLoaded(Object embeddedBean) {
}
@Override
public boolean isEmbeddedNewOrDirty(Object embeddedBean) {
return false;
}
@Override
public Object getOrigValue(int propertyIndex) {
return null;
}
@Override
public int findProperty(String propertyName) {
return 0;
}
@Override
public String getProperty(int propertyIndex) {
return null;
}
@Override
public int getPropertyLength() {
return 0;
}
@Override
public void setPropertyLoaded(String propertyName, boolean loaded) {
}
@Override
public void setPropertyUnloaded(int propertyIndex) {
}
@Override
public void setLoadedProperty(int propertyIndex) {
}
@Override
public void setLoadedPropertyAll() {
}
@Override
public boolean isLoadedProperty(int propertyIndex) {
return false;
}
@Override
public boolean isChangedProperty(int propertyIndex) {
return false;
}
@Override
public boolean isDirtyProperty(int propertyIndex) {
return false;
}
@Override
public void markPropertyAsChanged(int propertyIndex) {
}
@Override
public void setChangedProperty(int propertyIndex) {
}
@Override
public void setChangeLoaded(int propertyIndex) {
}
@Override
public void setEmbeddedPropertyDirty(int propertyIndex) {
}
@Override
public void setOriginalValue(int propertyIndex, Object value) {
}
@Override
public void setOriginalValueForce(int propertyIndex, Object value) {
}
@Override
public void setNewBeanForUpdate() {
}
@Override
public Set<String> getLoadedPropertyNames() {
return Collections.emptySet();
}
@Override
public boolean[] getDirtyProperties() {
return new boolean[0];
}
@Override
public Set<String> getDirtyPropertyNames() {
return Collections.emptySet();
}
@Override
public void addDirtyPropertyNames(Set<String> props, String prefix) {
}
@Override
public boolean hasDirtyProperty(Set<String> propertyNames) {
return false;
}
@Override
public Map<String, ValuePair> getDirtyValues() {
return Collections.emptyMap();
}
@Override
public void addDirtyPropertyValues(Map<String, ValuePair> dirtyValues, String prefix) {
}
@Override
public void addDirtyPropertyValues(BeanDiffVisitor visitor) {
}
@Override
public StringBuilder getDirtyPropertyKey() {
return null;
}
@Override
public void addDirtyPropertyKey(StringBuilder sb) {
}
@Override
public StringBuilder getLoadedPropertyKey() {
return null;
}
@Override
public boolean[] getLoaded() {
return new boolean[0];
}
@Override
public int getLazyLoadPropertyIndex() {
return 0;
}
@Override
public String getLazyLoadProperty() {
return null;
}
@Override
public void loadBean(int loadProperty) {
}
@Override
public void loadBeanInternal(int loadProperty, BeanLoader loader) {
}
@Override
public void initialisedMany(int propertyIndex) {
}
@Override
public void preGetterCallback(int propertyIndex) {
}
@Override
public void preGetId() {
}
@Override
public void preGetter(int propertyIndex) {
}
@Override
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
}
@Override
public void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
}
@Override
public void setDirtyStatus() {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, Object oldValue, Object newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, boolean oldValue, boolean newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, int oldValue, int newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, double oldValue, double newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, float oldValue, float newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, short oldValue, short newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, char oldValue, char newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, byte oldValue, byte newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, char[] oldValue, char[] newValue) {
}
@Override
public void preSetter(boolean intercept, int propertyIndex, byte[] oldValue, byte[] newValue) {
}
@Override
public void setOldValue(int propertyIndex, Object oldValue) {
}
@Override
public int getSortOrder() {
return 0;
}
@Override
public void setSortOrder(int sortOrder) {
}
@Override
public void setDeletedFromCollection(boolean deletedFromCollection) {
}
@Override
public boolean isOrphanDelete() {
return false;
}
@Override
public void setLoadError(int propertyIndex, Exception t) {
}
@Override
public Map<String, Exception> getLoadErrors() {
return null;
}
@Override
public boolean isChangedProp(int i) {
return false;
}
@Override
public MutableValueInfo mutableInfo(int propertyIndex) {
return null;
}
@Override
public void mutableInfo(int propertyIndex, MutableValueInfo info) {
}
@Override
public void mutableNext(int propertyIndex, MutableValueNext next) {
}
@Override
public String mutableNext(int propertyIndex) {
return null;
}
}
File diff suppressed because it is too large Load Diff
@@ -29,9 +29,10 @@ public final class TenantAwareCache implements ServerCache {
/**
* Return the underlying ServerCache that is being delegated to.
*/
@SuppressWarnings("unchecked")
@Override
public <T> T unwrap(Class<T> cls) {
return (T)delegate;
return (T) delegate;
}
@Override
@@ -28,7 +28,7 @@ abstract class BaseCollectionHelp<T> implements BeanCollectionHelp<T> {
}
@Override
public void setLoader(BeanCollectionLoader loader) {
public final void setLoader(BeanCollectionLoader loader) {
this.loader = loader;
}
@@ -43,7 +43,7 @@ abstract class BaseCollectionHelp<T> implements BeanCollectionHelp<T> {
@SuppressWarnings("rawtypes")
@Override
public Collection underlying(Object value) {
public final Collection underlying(Object value) {
if (value instanceof BeanCollection) {
return ((BeanCollection)value).getActualDetails();
} else {
@@ -51,7 +51,7 @@ abstract class BaseCollectionHelp<T> implements BeanCollectionHelp<T> {
}
}
void jsonWriteCollection(SpiJsonWriter ctx, String name, Collection<?> list) throws IOException {
final void jsonWriteCollection(SpiJsonWriter ctx, String name, Collection<?> list) throws IOException {
if (!list.isEmpty() || ctx.isIncludeEmpty()) {
ctx.beginAssocMany(name);
for (Object bean : list) {
@@ -47,6 +47,11 @@ public interface BeanCollectionHelp<T> extends CQueryCollectionAdd<T> {
*/
BeanCollection<T> createEmpty(EntityBean bean);
/**
* Create and return an empty 'vanilla' collection that does not support lazy loading.
*/
Object createEmptyReference();
/**
* Add a bean to the List Set or Map.
*/
@@ -86,7 +86,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
private final ConcurrentHashMap<String, ElPropertyDeploy> elDeployCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, ElComparator<T>> comparatorCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, STreeProperty> dynamicProperty = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Map<String,String>> pathMaps = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Map<String, String>> pathMaps = new ConcurrentHashMap<>();
private final Map<String, SpiRawSql> namedRawSql;
private final Map<String, String> namedQuery;
@@ -1765,6 +1765,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
return createEntityBean(false);
}
@Override
public EntityBean createEntityBean2(boolean readOnlyNoIntercept) {
if (readOnlyNoIntercept) {
return (EntityBean) prototypeEntityBean._ebean_newInstanceReadOnly();
}
return createEntityBean(false);
}
/**
* Create an entity bean for JSON marshalling (which differs for the element collection case).
*/
@@ -2879,7 +2887,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
for (BeanPropertyAssocMany<?> many : propertiesManySave) {
if (ebi.isLoadedProperty(many.propertyIndex())) {
final Object value = many.getValue(bean);
if (value instanceof BeanCollection && ((BeanCollection<?>)value).hasModifications() || value != null) {
if (value instanceof BeanCollection && ((BeanCollection<?>) value).hasModifications() || value != null) {
return true;
}
}
@@ -11,6 +11,7 @@ import io.ebeaninternal.api.json.SpiJsonWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -27,8 +28,7 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
if (bc instanceof BeanList<?>) {
BeanList<?> bl = (BeanList<?>) bc;
if (bl.getActualList() == null) {
@@ -42,12 +42,17 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public BeanCollection<T> createEmptyNoParent() {
public final Object createEmptyReference() {
return Collections.EMPTY_LIST;
}
@Override
public final BeanCollection<T> createEmptyNoParent() {
return new BeanList<>();
}
@Override
public BeanCollection<T> createEmpty(EntityBean parentBean) {
public final BeanCollection<T> createEmpty(EntityBean parentBean) {
BeanList<T> beanList = new BeanList<>(loader, parentBean, propertyName);
if (many != null) {
beanList.setModifyListening(many.modifyListenMode());
@@ -56,29 +61,23 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public BeanCollection<T> createReference(EntityBean parentBean) {
public final BeanCollection<T> createReference(EntityBean parentBean) {
BeanList<T> beanList = new BeanList<>(loader, parentBean, propertyName);
beanList.setModifyListening(many.modifyListenMode());
return beanList;
}
@Override
public void refresh(SpiEbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
public final void refresh(SpiEbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
BeanList<?> newBeanList = (BeanList<?>) server.findList(query, t);
refresh(newBeanList, parentBean);
}
@Override
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
BeanList<?> newBeanList = (BeanList<?>) bc;
List<?> currentList = (List<?>) many.getValue(parentBean);
newBeanList.setModifyListening(many.modifyListenMode());
if (currentList == null) {
// the currentList is null? Not really expecting this...
many.setValue(parentBean, newBeanList);
@@ -96,8 +95,7 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
public final void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
List<?> list;
if (collection instanceof BeanCollection<?>) {
BeanList<?> beanList = (BeanList<?>) collection;
@@ -114,7 +112,6 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
} else {
list = (List<?>) collection;
}
jsonWriteCollection(ctx, name, list);
}
@@ -10,6 +10,7 @@ import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.json.SpiJsonWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -36,13 +37,11 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
@Override
@SuppressWarnings("unchecked")
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
if (mapKey == null) {
mapKey = many.mapKey();
}
BeanProperty beanProp = targetDescriptor.beanProperty(mapKey);
if (bc instanceof BeanMap<?, ?>) {
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
Map<Object, Object> actualMap = bm.getActualMap();
@@ -57,10 +56,9 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
}
}
static class Adder implements BeanCollectionAdd {
static final class Adder implements BeanCollectionAdd {
private final BeanProperty beanProperty;
private final Map<Object, Object> map;
Adder(BeanProperty beanProperty, Map<Object, Object> map) {
@@ -76,13 +74,17 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public BeanCollection<T> createEmptyNoParent() {
public final Object createEmptyReference() {
return Collections.EMPTY_MAP;
}
@Override
public final BeanCollection<T> createEmptyNoParent() {
return new BeanMap<>();
}
@Override
public BeanCollection<T> createEmpty(EntityBean ownerBean) {
public final BeanCollection<T> createEmpty(EntityBean ownerBean) {
BeanMap<?, T> beanMap = new BeanMap<>(loader, ownerBean, propertyName);
if (many != null) {
beanMap.setModifyListening(many.modifyListenMode());
@@ -92,7 +94,6 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
@Override
public void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck) {
if (bean == null) {
((BeanMap<?, ?>) collection).internalPutNull();
} else {
@@ -104,8 +105,7 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public BeanCollection<T> createReference(EntityBean parentBean) {
public final BeanCollection<T> createReference(EntityBean parentBean) {
BeanMap beanMap = new BeanMap(loader, parentBean, propertyName);
if (many != null) {
beanMap.setModifyListening(many.modifyListenMode());
@@ -114,14 +114,13 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public void refresh(SpiEbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
public final void refresh(SpiEbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) server.findMap(query, t);
refresh(newBeanMap, parentBean);
}
@Override
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) bc;
Map<?, ?> current = (Map<?, ?>) many.getValue(parentBean);
@@ -143,8 +142,7 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
public final void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
Map<?, ?> map;
if (collection instanceof BeanCollection<?>) {
BeanMap<?, ?> bc = (BeanMap<?, ?>) collection;
@@ -15,7 +15,6 @@ public final class BeanMapHelpElement<T> extends BeanMapHelp<T> {
public void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck) {
Object key = bean._ebean_getField(0);
Object val = bean._ebean_getField(1);
BeanMap<?, ?> map = ((BeanMap<?, ?>) collection);
if (withCheck) {
map.internalPutWithCheck(key, val);
@@ -601,6 +601,11 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
return mapKey;
}
@Override
public void createEmptyReference(EntityBean localBean) {
setValue(localBean, help.createEmptyReference());
}
@Override
public BeanCollection<?> createReference(EntityBean localBean, boolean forceNewReference) {
return forceNewReference ? createReference(localBean) : createReferenceIfNull(localBean);
@@ -10,6 +10,7 @@ import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.json.SpiJsonWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -33,7 +34,7 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
if (bc instanceof BeanSet<?>) {
BeanSet<?> beanSet = (BeanSet<?>) bc;
if (beanSet.getActualSet() == null) {
@@ -46,12 +47,17 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public BeanCollection<T> createEmptyNoParent() {
public final Object createEmptyReference() {
return Collections.EMPTY_SET;
}
@Override
public final BeanCollection<T> createEmptyNoParent() {
return new BeanSet<>();
}
@Override
public BeanCollection<T> createEmpty(EntityBean ownerBean) {
public final BeanCollection<T> createEmpty(EntityBean ownerBean) {
BeanSet<T> beanSet = new BeanSet<>(loader, ownerBean, propertyName);
if (many != null) {
beanSet.setModifyListening(many.modifyListenMode());
@@ -60,20 +66,20 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public BeanCollection<T> createReference(EntityBean parentBean) {
public final BeanCollection<T> createReference(EntityBean parentBean) {
BeanSet<T> beanSet = new BeanSet<>(loader, parentBean, propertyName);
beanSet.setModifyListening(many.modifyListenMode());
return beanSet;
}
@Override
public void refresh(SpiEbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
public final void refresh(SpiEbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
BeanSet<?> newBeanSet = (BeanSet<?>) server.findSet(query, t);
refresh(newBeanSet, parentBean);
}
@Override
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
BeanSet<?> newBeanSet = (BeanSet<?>) bc;
Set<?> current = (Set<?>) many.getValue(parentBean);
newBeanSet.setModifyListening(many.modifyListenMode());
@@ -94,7 +100,7 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
}
@Override
public void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
public final void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
Set<?> set;
if (collection instanceof BeanCollection<?>) {
BeanSet<?> bc = (BeanSet<?>) collection;
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.InterceptReadWrite;
final class ElementEntityBean implements EntityBean {
@@ -13,7 +14,7 @@ final class ElementEntityBean implements EntityBean {
ElementEntityBean(String[] properties) {
this.properties = properties;
this.intercept = new EntityBeanIntercept(this);
this.intercept = new InterceptReadWrite(this);
}
@Override
@@ -33,6 +33,11 @@ public interface STreePropertyAssocMany extends STreePropertyAssoc {
*/
BeanCollection<?> createReference(EntityBean localBean, boolean forceNewReference);
/**
* Populate the collection for read-only disabled lazy loading (aka Java Collections non mutable empty collection).
*/
void createEmptyReference(EntityBean localBean);
/**
* Return true if the property has a join table.
*/
@@ -79,6 +79,11 @@ public interface STreeType {
*/
EntityBean createEntityBean();
/**
* Create a new entity bean instance with option for read only optimisation.
*/
EntityBean createEntityBean2(boolean readOnlyNoIntercept);
/**
* Put the entity bean into the persistence context.
*/
@@ -50,6 +50,7 @@ public final class SqlTreeBuilder {
*/
private final boolean rawNoId;
private final boolean disableLazyLoad;
private final boolean readOnly;
private final SpiQuery.TemporalMode temporalMode;
private SqlTreeNode rootNode;
private boolean sqlDistinct;
@@ -63,6 +64,7 @@ public final class SqlTreeBuilder {
this.desc = request.descriptor();
this.rawNoId = rawNoId;
this.disableLazyLoad = request.query().isDisableLazyLoading();
this.readOnly = Boolean.TRUE.equals(request.query().isReadOnly());
this.query = null;
this.subQuery = false;
this.distinctOnPlatform = false;
@@ -88,6 +90,7 @@ public final class SqlTreeBuilder {
this.query = request.query();
this.temporalMode = SpiQuery.TemporalMode.of(query);
this.disableLazyLoad = query.isDisableLazyLoading();
this.readOnly = Boolean.TRUE.equals(query.isReadOnly());
this.subQuery = Type.SQ_EXISTS == query.getType()
|| Type.SQ_IN == query.getType()
|| Type.ID_LIST == query.getType()
@@ -309,13 +312,13 @@ public final class SqlTreeBuilder {
if (baseTable == null) {
baseTable = desc.baseTable(temporalMode);
}
return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany, temporalMode, disableLazyLoad, sqlDistinct, baseTable);
return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany, temporalMode, disableLazyLoad, readOnly, sqlDistinct, baseTable);
} else if (prop instanceof STreePropertyAssocMany) {
return new SqlTreeNodeManyRoot(prefix, (STreePropertyAssocMany) prop, props, myList, withId(), temporalMode, disableLazyLoad);
return new SqlTreeNodeManyRoot(prefix, (STreePropertyAssocMany) prop, props, myList, withId(), temporalMode, disableLazyLoad, readOnly);
} else {
return new SqlTreeNodeBean(prefix, prop, props, myList, withId(), temporalMode, disableLazyLoad);
return new SqlTreeNodeBean(prefix, prop, props, myList, withId(), temporalMode, disableLazyLoad, readOnly);
}
}
@@ -28,6 +28,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
final boolean readId;
private final boolean readIdNormal;
private final boolean disableLazyLoad;
private final boolean readOnlyNoIntercept;
private final InheritInfo inheritInfo;
final String prefix;
private final Map<String, String> pathMap;
@@ -49,6 +50,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
this.readId = node.readId;
this.readIdNormal = readId && !temporalVersions;
this.disableLazyLoad = node.disableLazyLoad;
this.readOnlyNoIntercept = disableLazyLoad && node.readOnly;
this.partialObject = node.partialObject;
this.properties = node.properties;
this.pathMap = node.pathMap;
@@ -145,7 +147,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
void initBeanType() throws SQLException {
localDesc = desc;
localBean = desc.createEntityBean();
localBean = desc.createEntityBean2(readOnlyNoIntercept);
localIdBinder = idBinder;
}
@@ -282,14 +284,18 @@ class SqlTreeLoadBean implements SqlTreeLoad {
boolean forceNewReference = queryMode == Mode.REFRESH_BEAN;
for (STreePropertyAssocMany many : localDesc.propsMany()) {
if (many != fetchedMany) {
// create a proxy for the many (deferred fetching)
BeanCollection<?> ref = many.createReference(localBean, forceNewReference);
if (ref != null) {
if (disableLazyLoad) {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(many.asMany(), ref);
if (readOnlyNoIntercept) {
many.createEmptyReference(localBean);
} else {
// create a proxy for the many (deferred fetching)
BeanCollection<?> ref = many.createReference(localBean, forceNewReference);
if (ref != null) {
if (disableLazyLoad) {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(many.asMany(), ref);
}
}
}
}
@@ -38,6 +38,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
final boolean readId;
final boolean readIdNormal;
final boolean disableLazyLoad;
final boolean readOnly;
final InheritInfo inheritInfo;
final String prefix;
final Map<String, String> pathMap;
@@ -57,16 +58,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
* Construct for leaf node.
*/
SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, SqlTreeProperties props,
List<SqlTreeNode> myChildren, boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
this(prefix, beanProp, beanProp.target(), props, myChildren, withId, null, temporalMode, disableLazyLoad);
List<SqlTreeNode> myChildren, boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad, boolean readOnly) {
this(prefix, beanProp, beanProp.target(), props, myChildren, withId, null, temporalMode, disableLazyLoad, readOnly);
}
/**
* Construct for root node.
*/
SqlTreeNodeBean(STreeType desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId,
STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
this(null, null, desc, props, myList, withId, many, temporalMode, disableLazyLoad);
STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad, boolean readOnly) {
this(null, null, desc, props, myList, withId, many, temporalMode, disableLazyLoad, readOnly);
}
/**
@@ -74,7 +75,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
*/
private SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, STreeType desc, SqlTreeProperties props,
List<SqlTreeNode> myChildren, boolean withId, STreePropertyAssocMany lazyLoadParent,
SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad, boolean readOnly) {
this.lazyLoadParent = lazyLoadParent;
this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.idBinder();
this.prefix = prefix;
@@ -91,6 +92,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
this.readId = !aggregationRoot && withId && desc.hasId();
this.readIdNormal = readId && !temporalVersions;
this.disableLazyLoad = disableLazyLoad || !readIdNormal || desc.isRawSqlBased();
this.readOnly = readOnly;
this.partialObject = props.isPartialObject();
this.properties = props.getProps();
this.children = myChildren == null ? Collections.emptyList() : myChildren;
@@ -10,8 +10,8 @@ final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
final STreePropertyAssocMany manyProp;
SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List<SqlTreeNode> myList,
boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
super(prefix, prop, props, myList, withId, temporalMode, disableLazyLoad);
boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad, boolean readOnly) {
super(prefix, prop, props, myList, withId, temporalMode, disableLazyLoad, readOnly);
this.manyProp = prop;
}
@@ -20,9 +20,9 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean {
* Specify for SqlSelect to include an Id property or not.
*/
SqlTreeNodeRoot(STreeType desc, SqlTreeProperties props, List<SqlTreeNode> myList, boolean withId, TableJoin includeJoin,
STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad, boolean sqlDistinct, String baseTable) {
STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad, boolean readOnly, boolean sqlDistinct, String baseTable) {
super(desc, props, myList, withId, many, temporalMode, disableLazyLoad);
super(desc, props, myList, withId, many, temporalMode, disableLazyLoad, readOnly);
this.includeJoin = includeJoin;
this.sqlDistinct = sqlDistinct;
this.baseTable = baseTable;
@@ -1 +1 @@
ebean-version: 133
ebean-version: 141
+1
View File
@@ -0,0 +1 @@
synthetic: false
@@ -0,0 +1 @@
ebean-version: 141
@@ -0,0 +1 @@
synthetic: false
@@ -1,15 +1,25 @@
package org.tests.query;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.InterceptReadOnly;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Query;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestQueryOrderById extends BaseTestCase {
@Test
public void orderById_default_expectNotOrderById() {
ResetBasicData.reset();
Query<Customer> query = DB.find(Customer.class)
.select("id,name")
@@ -17,12 +27,20 @@ public class TestQueryOrderById extends BaseTestCase {
.setFirstRow(1)
.setMaxRows(5);
query.findList();
query.setReadOnly(true).setDisableLazyLoading(true);
List<Customer> list = query.findList();
if (isSqlServer() || isDb2()) {
assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id offset 1 rows fetch next 5 rows only");
} else if (!isOracle()) {
assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id limit 5 offset 1");
}
assertThat(list).isNotEmpty();
Customer customer = list.get(0);
EntityBeanIntercept intercept = ((EntityBean) customer)._ebean_getIntercept();
assertThat(intercept).isInstanceOf(InterceptReadOnly.class);
assertThat(customer.getOrders()).isSameAs(Collections.EMPTY_LIST);
assertThat(customer.getContacts()).isSameAs(Collections.EMPTY_LIST);
}
@Test
@@ -0,0 +1 @@
ebean-version: 141