From 74e0a16531862eaa5f2d88b1c38f5e73a40322c1 Mon Sep 17 00:00:00 2001
From: Rob Bygrave
Date: Mon, 26 Mar 2018 20:45:39 +1300
Subject: [PATCH] #1351 - ENH: Add named DtoQuery
Merge branch 'feature/namedDtoQuery' of https://github.com/hexagonframework/ebean into hexagonframework-feature/namedDtoQuery
---
src/main/java/io/ebean/EbeanServer.java | 18 ++---
.../server/core/DefaultServer.java | 21 +++---
.../server/core/InternalConfigXmlRead.java | 74 ++++++++++++++++---
.../server/core/InternalConfiguration.java | 55 +++-----------
.../server/deploy/BeanDescriptorManager.java | 15 ----
.../server/dto/DtoBeanDescriptor.java | 61 ++-------------
.../server/dto/DtoBeanManager.java | 68 ++++-------------
.../xmlmapping/XmlMappingReader.java | 17 +++--
.../ebeaninternal/xmlmapping/model/XmDto.java | 4 +-
.../xmlmapping/model/XmEbean.java | 7 +-
src/main/resources/ebean-1.0.xsd | 4 +-
src/test/java/io/ebean/NamedDtoQueryTest.java | 5 +-
.../ebeaninternal/api/TDSpiEbeanServer.java | 5 +-
src/test/resources/ebean.properties | 1 +
14 files changed, 139 insertions(+), 216 deletions(-)
diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java
index 78619886b..6fbc54b24 100644
--- a/src/main/java/io/ebean/EbeanServer.java
+++ b/src/main/java/io/ebean/EbeanServer.java
@@ -8,6 +8,12 @@ import io.ebean.plugin.Property;
import io.ebean.plugin.SpiServer;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.persistence.NonUniqueResultException;
+import javax.persistence.OptimisticLockException;
+import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -16,11 +22,6 @@ import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.persistence.NonUniqueResultException;
-import javax.persistence.OptimisticLockException;
-import javax.persistence.PersistenceException;
/**
* Provides the API for fetching and saving beans to a particular DataSource.
@@ -104,7 +105,6 @@ public interface EbeanServer {
*
* @param shutdownDataSource if true then shutdown the underlying DataSource if it is the EbeanORM
* DataSource implementation.
- * DataSource implementation.
* @param deregisterDriver if true then deregister the JDBC driver if it is the EbeanORM
* DataSource implementation.
*/
@@ -444,9 +444,9 @@ public interface EbeanServer {
* They do not need to be registered with Ebean before use.
*
*
- * @param dtoType The type of the DTO bean the rows will be mapped into.
- * @param namedQuery The name of the query
- * @param The type of the DTO bean.
+ * @param dtoType The type of the DTO bean the rows will be mapped into.
+ * @param namedQuery The name of the query
+ * @param The type of the DTO bean.
*/
DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery);
diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
index da3d5af00..b4827d155 100644
--- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
@@ -105,6 +105,13 @@ import io.ebeaninternal.server.transaction.TransactionManager;
import io.ebeaninternal.util.ParamTypeHelper;
import io.ebeaninternal.util.ParamTypeHelper.TypeInfo;
import io.ebeanservice.docstore.api.DocStoreIntegration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.NonUniqueResultException;
+import javax.persistence.OptimisticLockException;
+import javax.persistence.PersistenceException;
+import javax.sql.DataSource;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -119,12 +126,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
-import javax.persistence.NonUniqueResultException;
-import javax.persistence.OptimisticLockException;
-import javax.persistence.PersistenceException;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* The default server side implementation of EbeanServer.
@@ -1001,11 +1002,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery) {
DtoBeanDescriptor descriptor = dtoBeanManager.getDescriptor(dtoType);
- SpiRawSql rawSql = descriptor.getNamedRawSql(namedQuery);
- if (rawSql != null) {
- return new DefaultDtoQuery<>(this, descriptor, rawSql.getSql().getUnparsedSql());
+ String sql = descriptor.getNamedRawSql(namedQuery);
+ if (sql == null) {
+ throw new PersistenceException("No named query called " + namedQuery + " for bean:" + dtoType.getName());
}
- throw new PersistenceException("No named query called " + namedQuery + " for bean:" + dtoType.getName());
+ return new DefaultDtoQuery<>(this, descriptor, sql);
}
@Override
diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java b/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java
index 401dbcd17..8bb1b9be7 100644
--- a/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java
+++ b/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java
@@ -1,39 +1,49 @@
package io.ebeaninternal.server.core;
import io.ebean.config.ServerConfig;
+import io.ebeaninternal.server.dto.DtoNamedQueries;
import io.ebeaninternal.xmlmapping.XmlMappingReader;
+import io.ebeaninternal.xmlmapping.model.XmDto;
import io.ebeaninternal.xmlmapping.model.XmEbean;
+import io.ebeaninternal.xmlmapping.model.XmRawSql;
import org.avaje.classpath.scanner.ClassPathScanner;
import org.avaje.classpath.scanner.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+/**
+ * Reads the Xml deployment information.
+ */
class InternalConfigXmlRead {
private static final Logger log = LoggerFactory.getLogger(InternalConfigXmlRead.class);
private final ServerConfig serverConfig;
+ private final ClassLoader classLoader;
+
+ private final Map, DtoNamedQueries> dtoNamedQueries = new HashMap<>();
+
+ private List xmlEbeanList;
+
InternalConfigXmlRead(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
+ this.classLoader = serverConfig.getClassLoadConfig().getClassLoader();
+
+ init();
}
- List build() {
-
- ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
- List xmlEbeanList = XmlMappingReader.readByResourceName(classLoader, "ebean.xml");
-
- List resources = searchXmlMapping();
- xmlEbeanList.addAll(XmlMappingReader.readByResourceList(resources));
-
- return xmlEbeanList;
+ private void init() {
+ this.xmlEbeanList = XmlMappingReader.readByResourceName(classLoader, "ebean.xml");
+ xmlEbeanList.addAll(XmlMappingReader.readByResourceList(xmlMappingResources()));
}
-
- private List searchXmlMapping() {
+ private List xmlMappingResources() {
List scanners = ClassPathScanners.find(serverConfig);
List mappingLocations = serverConfig.getMappingLocations();
List resourceList = new ArrayList<>();
@@ -52,5 +62,47 @@ class InternalConfigXmlRead {
return resourceList;
}
+ /**
+ * Return the XML deployment information for entity beans.
+ */
+ List xmlDeployment() {
+ return xmlEbeanList;
+ }
+
+ /**
+ * Return the named queries for Dto beans.
+ */
+ Map, DtoNamedQueries> readDtoMapping() {
+ for (XmEbean mapping : xmlEbeanList) {
+ List dtoList = mapping.getDto();
+ for (XmDto dto : dtoList) {
+ readDtoMapping(dto);
+ }
+ }
+
+ return dtoNamedQueries;
+ }
+
+ private void readDtoMapping(XmDto dto) {
+
+ String dtoClassName = dto.getClazz();
+ Class> dtoClass;
+ try {
+ dtoClass = Class.forName(dtoClassName, false, classLoader);
+ } catch (Exception e) {
+ log.error("Could not load dto bean class " + dtoClassName + " for ebean xml entry");
+ return;
+ }
+
+ DtoNamedQueries namedQueries = dtoNamedQueries.computeIfAbsent(dtoClass, aClass -> new DtoNamedQueries());
+
+ for (XmRawSql sql : dto.getRawSql()) {
+ namedQueries.addRawSql(sql.getName(), sql.getQuery().getValue());
+ }
+
+ if (!dto.getNamedQuery().isEmpty()) {
+ log.error("Only raw-sql named queries supported for DTO beans - bean:" + dtoClass);
+ }
+ }
}
diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java
index 82d395aed..31aea3889 100644
--- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java
+++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java
@@ -69,23 +69,19 @@ import io.ebeaninternal.server.transaction.TransactionManagerOptions;
import io.ebeaninternal.server.transaction.TransactionScopeManager;
import io.ebeaninternal.server.type.DefaultTypeManager;
import io.ebeaninternal.server.type.TypeManager;
-import io.ebeaninternal.xmlmapping.XmlMappingReader;
-import io.ebeaninternal.xmlmapping.model.XmEbean;
import io.ebeanservice.docstore.api.DocStoreFactory;
import io.ebeanservice.docstore.api.DocStoreIntegration;
import io.ebeanservice.docstore.api.DocStoreUpdateProcessor;
import io.ebeanservice.docstore.none.NoneDocStoreFactory;
+import org.avaje.datasource.DataSourcePool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
-import javax.sql.DataSource;
-import org.avaje.classpath.scanner.ClassPathScanner;
-import org.avaje.classpath.scanner.Resource;
-import org.avaje.classpath.scanner.ResourceFilter;
-import org.avaje.datasource.DataSourcePool;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Used to extend the ServerConfig with additional objects used to configure and
@@ -138,8 +134,6 @@ public class InternalConfiguration {
private final MultiValueBind multiValueBind;
- private List xmlEbeanList = new ArrayList<>();
-
public InternalConfiguration(ClusterManager clusterManager,
SpiCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
ServerConfig serverConfig, BootupClasses bootupClasses) {
@@ -159,20 +153,14 @@ public class InternalConfiguration {
this.multiValueBind = createMultiValueBind(databasePlatform.getPlatform());
this.deployInherit = new DeployInherit(bootupClasses);
- xmlEbeanList = XmlMappingReader.readByResourceName(serverConfig.getClassLoadConfig().getClassLoader(),
- "ebean.xml");
- List searchXmlMapping = searchXmlMapping();
- xmlEbeanList.addAll(XmlMappingReader.readByResourceList(serverConfig.getClassLoadConfig().getClassLoader(),
- searchXmlMapping));
-
this.deployCreateProperties = new DeployCreateProperties(typeManager);
this.deployUtil = new DeployUtil(typeManager, serverConfig);
- this.dtoBeanManager = new DtoBeanManager(typeManager);
- dtoBeanManager.readXmlMapping(serverConfig.getClassLoadConfig().getClassLoader(),
- xmlEbeanList);
+ InternalConfigXmlRead xmlRead = new InternalConfigXmlRead(serverConfig);
+
+ this.dtoBeanManager = new DtoBeanManager(typeManager, xmlRead.readDtoMapping());
this.beanDescriptorManager = new BeanDescriptorManager(this);
- Map asOfTableMapping = beanDescriptorManager.deploy(xmlEbeanList);
+ Map asOfTableMapping = beanDescriptorManager.deploy(xmlRead.xmlDeployment());
Map draftTableMap = beanDescriptorManager.getDraftTableMap();
beanDescriptorManager.scheduleBackgroundTrim();
@@ -181,31 +169,6 @@ public class InternalConfiguration {
this.cQueryEngine = new CQueryEngine(serverConfig, databasePlatform, binder, asOfTableMapping, draftTableMap);
}
- private List searchXmlMapping() {
- List scanners = ClassPathScanners.find(serverConfig);
- List mappingLocations = serverConfig.getMappingLocations();
- List resourceList = new ArrayList<>();
-
- long st = System.currentTimeMillis();
- if (mappingLocations != null && !mappingLocations.isEmpty()) {
- for (ClassPathScanner finder : scanners) {
- for (String mappingLocation : mappingLocations) {
- resourceList.addAll(finder.scanForResources(mappingLocation, new ResourceFilter() {
-
- @Override
- public boolean isMatch(String resourceName) {
- return resourceName.endsWith(".xml");
- }
- }));
- }
- }
- }
-
- long searchTime = System.currentTimeMillis() - st;
- logger.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime);
- return resourceList;
- }
-
/**
* Create and return the ExpressionFactory based on configuration and database platform.
*/
diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java
index 6be9dd585..0e6814365 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java
@@ -26,7 +26,6 @@ import io.ebeaninternal.api.ConcurrencyMode;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.TransactionEventTable;
import io.ebeaninternal.server.cache.SpiCacheManager;
-import io.ebeaninternal.server.core.ClassPathScanners;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.core.InternalConfiguration;
import io.ebeaninternal.server.core.Message;
@@ -57,7 +56,6 @@ import io.ebeaninternal.server.query.CQueryPlan;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeInteger;
import io.ebeaninternal.server.type.TypeManager;
-import io.ebeaninternal.xmlmapping.XmlMappingReader;
import io.ebeaninternal.xmlmapping.model.XmAliasMapping;
import io.ebeaninternal.xmlmapping.model.XmColumnMapping;
import io.ebeaninternal.xmlmapping.model.XmEbean;
@@ -66,9 +64,6 @@ import io.ebeaninternal.xmlmapping.model.XmNamedQuery;
import io.ebeaninternal.xmlmapping.model.XmRawSql;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
import io.ebeanservice.docstore.api.DocStoreFactory;
-import org.avaje.classpath.scanner.ClassPathScanner;
-import org.avaje.classpath.scanner.Resource;
-import org.avaje.classpath.scanner.ResourceFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,17 +71,12 @@ import javax.persistence.MappedSuperclass;
import javax.persistence.PersistenceException;
import javax.persistence.Transient;
import javax.sql.DataSource;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -1064,11 +1054,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
unidirectional.setDbRead(true);
unidirectional.setDbInsertable(true);
unidirectional.setDbUpdateable(false);
-
- targetDesc.setUnidirectional(unidirectional);
-
- // specify table and table alias...
- BeanTable beanTable = getBeanTable(owningType);
unidirectional.setBeanTable(beanTable);
unidirectional.setName(beanTable.getBaseTable());
unidirectional.setJoinType(true);
diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java
index 0e8f4b42f..10f2a2cdc 100644
--- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java
+++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java
@@ -1,9 +1,7 @@
package io.ebeaninternal.server.dto;
import io.ebean.meta.MetricVisitor;
-import io.ebeaninternal.server.rawsql.SpiRawSql;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
+
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -12,25 +10,18 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class DtoBeanDescriptor {
- private static final Map EMPTY_NAMED_QUERY = new HashMap<>();
-
- private static final Map EMPTY_RAW_MAP = new HashMap<>();
-
private final Map