#1571 - NPE in cacheable bean with embeddedid on delete

This commit is contained in:
rob bygrave
2018-12-05 23:03:15 +13:00
parent 0405ceb96c
commit e4088c5fbe
16 changed files with 142 additions and 62 deletions
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataReader;
import java.sql.SQLException;
@@ -28,6 +29,24 @@ abstract class AssocOneHelp {
property.targetIdBinder.loadIgnore(ctx);
}
/**
* Read and return the property.
*/
Object read(DataReader reader) throws SQLException {
return property.read(reader);
}
/**
* Read and return the property setting value into the bean.
*/
Object readSet(DataReader reader, EntityBean bean) throws SQLException {
Object val = read(reader);
if (bean != null) {
property.setValue(bean, val);
}
return val;
}
/**
* Read and return the bean.
*/
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.type.DataReader;
import java.sql.SQLException;
@@ -9,14 +10,41 @@ import java.sql.SQLException;
*/
final class AssocOneHelpEmbedded extends AssocOneHelp {
public AssocOneHelpEmbedded(BeanPropertyAssocOne<?> property) {
AssocOneHelpEmbedded(BeanPropertyAssocOne<?> property) {
super(property);
}
@Override
void loadIgnore(DbReadContext ctx) {
for (int i = 0; i < property.embeddedProps.length; i++) {
property.embeddedProps[i].loadIgnore(ctx);
for (BeanProperty property : property.embeddedProps) {
property.loadIgnore(ctx);
}
}
@Override
Object readSet(DataReader reader, EntityBean bean) throws SQLException {
Object dbVal = read(reader);
if (bean != null) {
property.setValue(bean, dbVal);
}
return dbVal;
}
@Override
Object read(DataReader reader) throws SQLException {
EntityBean embeddedBean = property.targetDescriptor.createEntityBean();
boolean notNull = false;
for (BeanProperty property : property.embeddedProps) {
Object value = property.readSet(reader, embeddedBean);
if (value != null) {
notNull = true;
}
}
if (notNull) {
return embeddedBean;
} else {
return null;
}
}
@@ -39,8 +67,8 @@ final class AssocOneHelpEmbedded extends AssocOneHelp {
EntityBean embeddedBean = property.targetDescriptor.createEntityBean();
boolean notNull = false;
for (int i = 0; i < property.embeddedProps.length; i++) {
Object value = property.embeddedProps[i].readSet(ctx, embeddedBean);
for (BeanProperty property : property.embeddedProps) {
Object value = property.readSet(ctx, embeddedBean);
if (value != null) {
notNull = true;
}
@@ -55,8 +83,8 @@ final class AssocOneHelpEmbedded extends AssocOneHelp {
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
for (int i = 0; i < property.embeddedProps.length; i++) {
property.embeddedProps[i].appendSelect(ctx, subQuery);
for (BeanProperty property : property.embeddedProps) {
property.appendSelect(ctx, subQuery);
}
}
}
@@ -28,6 +28,7 @@ import io.ebeaninternal.server.query.STreeProperty;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.LocalEncryptedType;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeBoolean;
@@ -640,6 +641,23 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
}
@Override
public Object read(DataReader reader) throws SQLException {
return scalarType.read(reader);
}
public Object readSet(DataReader reader, EntityBean bean) throws SQLException {
try {
Object value = scalarType.read(reader);
if (bean != null) {
setValue(bean, value);
}
return value;
} catch (Exception e) {
throw new PersistenceException("Error readSet on " + descriptor + "." + name, e);
}
}
public Object read(DbReadContext ctx) throws SQLException {
return scalarType.read(ctx.getDataReader());
}
@@ -21,7 +21,8 @@ import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.query.STreePropertyAssocOne;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarDataReader;
import javax.persistence.PersistenceException;
import java.io.IOException;
@@ -434,8 +435,8 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
}
@Override
public ScalarType<?> getIdScalarType() {
return targetDescriptor.getIdProperty().getScalarType();
public ScalarDataReader<?> getIdReader() {
return targetDescriptor.getIdProperty();
}
/**
@@ -583,18 +584,23 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
}
}
@Override
public Object readSet(DataReader reader, EntityBean bean) throws SQLException {
return localHelp.readSet(reader, bean);
}
@Override
public Object read(DataReader reader) throws SQLException {
return localHelp.read(reader);
}
@Override
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
return localHelp.readSet(ctx, bean);
}
/**
* Read the data from the resultSet effectively ignoring it and returning null.
*/
@Override
public Object read(DbReadContext ctx) throws SQLException {
// just read the resultSet incrementing the column index
// pass in null for the bean so any data read is ignored
return localHelp.read(ctx);
}
@@ -1,9 +1,11 @@
package io.ebeaninternal.server.deploy;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
/**
* Dynamic property based on aggregation (max, min, avg, count).
@@ -36,6 +38,15 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase {
return aggregate;
}
@Override
public Object read(DataReader dataReader) throws SQLException {
try {
return scalarType.read(dataReader);
} catch (Exception e) {
throw new PersistenceException("Error loading on " + fullName, e);
}
}
@Override
public void load(SqlBeanLoad sqlBeanLoad) {
@@ -1,14 +1,14 @@
package io.ebeaninternal.server.query;
import io.ebean.util.JdbcClose;
import io.ebean.CountedValue;
import io.ebean.util.JdbcClose;
import io.ebeaninternal.api.SpiProfileTransactionEvent;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.type.RsetDataReader;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarDataReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,7 +60,7 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
private int rowCount;
private final ScalarType<?> scalarType;
private final ScalarDataReader<?> reader;
private final boolean containsCounts;
@@ -77,7 +77,7 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
this.desc = request.getBeanDescriptor();
this.predicates = predicates;
this.containsCounts = containsCounts;
this.scalarType = queryPlan.getSingleAttributeScalarType();
this.reader = queryPlan.getSingleAttributeScalarType();
query.setGeneratedSql(sql);
}
@@ -106,7 +106,7 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
List<Object> result = new ArrayList<>();
while (dataReader.next()) {
Object value = scalarType.read(dataReader);
Object value = reader.read(dataReader);
if (containsCounts) {
value = new CountedValue<>(value, dataReader.getLong());
}
@@ -15,7 +15,7 @@ import io.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.RsetDataReader;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarDataReader;
import io.ebeaninternal.server.util.Md5;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -286,8 +286,8 @@ public class CQueryPlan {
return stats.getLastQueryTime();
}
ScalarType<?> getSingleAttributeScalarType() {
return sqlTree.getRootNode().getSingleAttributeScalarType();
ScalarDataReader<?> getSingleAttributeScalarType() {
return sqlTree.getRootNode().getSingleAttributeReader();
}
/**
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.query;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.type.ScalarDataReader;
import io.ebeaninternal.server.type.ScalarType;
import java.util.List;
@@ -11,7 +12,7 @@ import java.util.List;
* <p>
* A BeanProperty or a dynamically created property based on formula.
*/
public interface STreeProperty {
public interface STreeProperty extends ScalarDataReader<Object> {
/**
* Return the property name.
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarDataReader;
public interface STreePropertyAssocOne extends STreePropertyAssoc {
@@ -13,7 +13,7 @@ public interface STreePropertyAssocOne extends STreePropertyAssoc {
/**
* Return the scalar type of the associated id property.
*/
ScalarType<?> getIdScalarType();
ScalarDataReader<?> getIdReader();
/**
* Returns true, if this relation has a foreign key.
@@ -5,7 +5,7 @@ import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarDataReader;
import java.sql.SQLException;
import java.util.List;
@@ -80,9 +80,9 @@ interface SqlTreeNode {
boolean hasMany();
/**
* Return the property for singleAttribute query.
* Return the reader for the single attribute query.
*/
ScalarType<?> getSingleAttributeScalarType();
ScalarDataReader<?> getSingleAttributeReader();
/**
* Return true if the query is known to only have a single property selected.
@@ -14,7 +14,7 @@ import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.deploy.id.IdBinder;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarDataReader;
import java.sql.SQLException;
import java.sql.Timestamp;
@@ -145,22 +145,22 @@ class SqlTreeNodeBean implements SqlTreeNode {
}
@Override
public ScalarType<?> getSingleAttributeScalarType() {
public ScalarDataReader<?> getSingleAttributeReader() {
if (properties == null || properties.length == 0) {
// if we have no property ask first children (in a distinct select with join)
if (children.length == 0) {
// expected to be a findIds query
return desc.getIdBinder().getBeanProperty().getScalarType();
return desc.getIdBinder().getBeanProperty();
}
return children[0].getSingleAttributeScalarType();
return children[0].getSingleAttributeReader();
}
if (properties[0] instanceof STreePropertyAssocOne) {
STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0];
if (assocOne.isAssocId()) {
return assocOne.getIdScalarType();
return assocOne.getIdReader();
}
}
return properties[0].getScalarType();
return properties[0];
}
private Map<String, String> createPathMap(String prefix, STreeType desc) {
@@ -76,7 +76,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
}
@Override
public ScalarType<?> getSingleAttributeScalarType() {
public ScalarType<?> getSingleAttributeReader() {
throw new IllegalStateException("No expected");
}
@@ -43,7 +43,7 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
}
@Override
public ScalarType<?> getSingleAttributeScalarType() {
public ScalarType<?> getSingleAttributeReader() {
throw new IllegalStateException("No expected");
}
@@ -12,14 +12,4 @@ public interface ScalarDataReader<T> {
*/
T read(DataReader dataReader) throws SQLException;
/**
* Ignore typically by moving the index position.
*/
void loadIgnore(DataReader dataReader);
/**
* Bind the value to the underlying preparedStatement.
*/
void bind(DataBind b, T value) throws SQLException;
}
@@ -1,10 +1,10 @@
package io.ebeaninternal.server.type;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import io.ebean.text.StringFormatter;
import io.ebean.text.StringParser;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import java.io.DataInput;
import java.io.DataOutput;
@@ -103,7 +103,6 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* Ignore the reading of this value. Typically this means moving the index
* position in the ResultSet.
*/
@Override
void loadIgnore(DataReader reader);
/**
@@ -113,7 +112,6 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* JDBC type.
* </p>
*/
@Override
void bind(DataBind bind, T value) throws SQLException;
/**