#1594 - Support loading of beans with invalid JSON content

Adjust to be per query via query.setAllowLoadErrors() rather than a
global config via ServerConfig.
This commit is contained in:
rob bygrave
2019-01-09 20:03:26 +13:00
parent 9fc10e8e04
commit 2b0669c2ae
10 changed files with 86 additions and 64 deletions
+21
View File
@@ -372,6 +372,27 @@ public interface Query<T> {
*/
Query<T> setAutoTune(boolean autoTune);
/**
* Execute the query allowing properties with invalid JSON to be collected and not fail the query.
* <pre>{@code
*
* // fetch a bean with JSON content
* EBasicJsonList bean= Ebean.find(EBasicJsonList.class)
* .setId(42)
* .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
* .findOne();
*
*
* // get the invalid JSON errors from the bean state
* Map<String, Exception> errors = server().getBeanState(bean).getLoadErrors();
*
* // If this map is not empty tell we have invalid JSON
* // and should try and fix the JSON content or inform the user
*
* }</pre>
*/
Query<T> setAllowLoadErrors();
/**
* Set the default lazy loading batch size to use.
* <p>
@@ -30,15 +30,9 @@ import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetaInfoManager;
import io.ebean.migration.MigrationRunner;
import io.ebean.plugin.LoadErrorHandler;
import io.ebean.util.StringHelper;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Clock;
import java.util.ArrayList;
import java.util.Collections;
@@ -527,10 +521,6 @@ public class ServerConfig {
*/
private boolean idGeneratorAutomatic = true;
private LoadErrorHandler loadErrorHandler = (bean, prop, fullName, e) -> {
throw new PersistenceException("Error loading on " + fullName, e);
};
/**
* Construct a Server Configuration for programmatically creating an EbeanServer.
*/
@@ -3016,13 +3006,6 @@ public class ServerConfig {
String mappingsProp = p.get("mappingLocations", null);
mappingLocations = getSearchList(mappingsProp, mappingLocations);
if (!p.getBoolean("failOnLoadError", true)) {
Logger logger = LoggerFactory.getLogger("io.ebean.SQL");
loadErrorHandler = (bean, prop, fullName, e) -> {
logger.error("Error loading on {}", fullName, e);
};
}
}
private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) {
@@ -3282,20 +3265,6 @@ public class ServerConfig {
this.idGeneratorAutomatic = idGeneratorAutomatic;
}
/**
* Returns the load error handler.
*/
public LoadErrorHandler getLoadErrorHandler() {
return loadErrorHandler;
}
/**
* Sets the loadErrorHandler.
*/
public void setLoadErrorHandler(LoadErrorHandler loadErrorHandler) {
this.loadErrorHandler = loadErrorHandler;
}
/**
* Return true if query plan capture is enabled.
*/
@@ -8,7 +8,6 @@ import io.ebean.PersistenceContextScope;
import io.ebean.ProfileLocation;
import io.ebean.Query;
import io.ebean.bean.CallStack;
import io.ebean.bean.EntityBean;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.PersistenceContext;
import io.ebean.event.readaudit.ReadEvent;
@@ -16,7 +15,6 @@ import io.ebean.plugin.BeanType;
import io.ebeaninternal.server.autotune.ProfilingListener;
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.query.CancelableQuery;
@@ -855,5 +853,5 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
/**
* Handles load errors.
*/
void handleLoadError(EntityBean bean, BeanProperty prop, String fullName, Exception e);
void handleLoadError(String fullName, Exception e);
}
@@ -94,6 +94,6 @@ public interface DbReadContext {
/**
* Handles a load error on given property.
*/
void handleLoadError(EntityBean bean, BeanProperty prop, String fullName, Exception e);
void handleLoadError(String fullName, Exception e);
}
@@ -52,9 +52,8 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase {
Object value;
try {
value = scalarType.read(sqlBeanLoad.ctx().getDataReader());
} catch (Exception e) {
sqlBeanLoad.ctx().handleLoadError(null, asTarget, fullName, e);
sqlBeanLoad.ctx().handleLoadError(fullName, e);
return;
}
if (asTarget != null) {
@@ -21,7 +21,6 @@ import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanCollectionHelp;
import io.ebeaninternal.server.deploy.BeanCollectionHelpFactory;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.type.DataBind;
@@ -817,8 +816,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
}
@Override
public void handleLoadError(EntityBean bean, BeanProperty prop, String fullName, Exception e) {
query.handleLoadError(bean, prop, fullName, e);
public void handleLoadError(String fullName, Exception e) {
query.handleLoadError(fullName, e);
}
public Set<String> getDependentTables() {
@@ -87,7 +87,7 @@ public class SqlBeanLoad {
} catch (Exception e) {
bean._ebean_getIntercept().setLoadError(prop.getPropertyIndex(), e);
ctx.handleLoadError(bean, prop, prop.getFullBeanName(), e);
ctx.handleLoadError(prop.getFullBeanName(), e);
return prop.getValue(bean);
}
}
@@ -25,7 +25,6 @@ import io.ebean.Transaction;
import io.ebean.UpdateQuery;
import io.ebean.Version;
import io.ebean.bean.CallStack;
import io.ebean.bean.EntityBean;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.ObjectGraphOrigin;
import io.ebean.bean.PersistenceContext;
@@ -47,7 +46,6 @@ import io.ebeaninternal.api.SpiQuerySecondary;
import io.ebeaninternal.server.autotune.ProfilingListener;
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.TableJoin;
@@ -57,6 +55,7 @@ import io.ebeaninternal.server.query.CancelableQuery;
import io.ebeaninternal.server.query.NativeSqlQueryPlanKey;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import javax.persistence.PersistenceException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
@@ -141,6 +140,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
private String lazyLoadManyPath;
private boolean allowLoadErrors;
/**
* Flag set for report/DTO beans when we may choose to explicitly include the Id property.
*/
@@ -329,8 +330,10 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public String profileEventId() {
switch (mode) {
case LAZYLOAD_BEAN: return FIND_ONE_LAZY;
case LAZYLOAD_MANY: return FIND_MANY_LAZY;
case LAZYLOAD_BEAN:
return FIND_ONE_LAZY;
case LAZYLOAD_MANY:
return FIND_MANY_LAZY;
default:
return type.profileEventId();
}
@@ -343,7 +346,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public Query<T> setProfileId(int profileId) {
this.profileId = (short)profileId;
this.profileId = (short) profileId;
return this;
}
@@ -409,6 +412,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
this.asOfBaseTable = true;
}
@Override
public DefaultOrmQuery<T> setAllowLoadErrors() {
this.allowLoadErrors = true;
return this;
}
@Override
public void incrementAsOfTableCount() {
asOfTableCount++;
@@ -463,7 +472,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public DefaultOrmQuery<T> setRawSql(RawSql rawSql) {
this.rawSql = (SpiRawSql)rawSql;
this.rawSql = (SpiRawSql) rawSql;
return this;
}
@@ -775,6 +784,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
copy.baseTable = baseTable;
copy.rootTableAlias = rootTableAlias;
copy.distinct = distinct;
copy.allowLoadErrors = allowLoadErrors;
copy.timeout = timeout;
copy.mapKey = mapKey;
copy.id = id;
@@ -1088,6 +1098,9 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
if (distinct) {
sb.append(",dist:");
}
if (allowLoadErrors) {
sb.append(",allowLoadErrors:");
}
if (disableLazyLoading) {
sb.append(",disLazy:");
}
@@ -1194,6 +1207,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
beanDescriptor.appendOrderById(this);
}
}
/**
* Calculate a hash based on the bind values used in the query.
* <p>
@@ -1278,7 +1292,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public boolean isBeanCacheGet() {
return useBeanCache.isGet() && beanDescriptor.isBeanCaching() ;
return useBeanCache.isGet() && beanDescriptor.isBeanCaching();
}
@Override
@@ -1337,7 +1351,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public DefaultOrmQuery<T> select(FetchGroup fetchGroup) {
this.detail = ((SpiFetchGroup)fetchGroup).detail();
this.detail = ((SpiFetchGroup) fetchGroup).detail();
return this;
}
@@ -1969,8 +1983,10 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
@Override
public void handleLoadError(EntityBean bean, BeanProperty prop, String fullName, Exception e) {
server.getServerConfig().getLoadErrorHandler().handleLoadError(bean, prop, fullName, e);
public void handleLoadError(String fullName, Exception e) {
if (!allowLoadErrors) {
throw new PersistenceException("Error loading on " + fullName, e);
}
}
@Override