#1351 - ENH: Add named DtoQuery

Merge branch 'feature/namedDtoQuery' of https://github.com/hexagonframework/ebean into hexagonframework-feature/namedDtoQuery
This commit is contained in:
Rob Bygrave
2018-03-26 20:45:22 +13:00
17 changed files with 893 additions and 90 deletions
+19 -6
View File
@@ -8,12 +8,6 @@ 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;
@@ -22,6 +16,11 @@ 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.
@@ -105,6 +104,7 @@ 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.
*/
@@ -437,6 +437,19 @@ public interface EbeanServer {
*/
<T> DtoQuery<T> findDto(Class<T> dtoType, String sql);
/**
* Create a named Query for DTO beans.
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with Ebean before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param namedQuery The name of the query
* @param <T> The type of the DTO bean.
*/
<T> DtoQuery<T> createNamedDtoQuery(Class<T> dtoType, String namedQuery);
/**
* Create a SqlQuery for executing native sql
* query statements.
@@ -489,8 +489,7 @@ public class ServerConfig {
private boolean defaultOrderById = false;
/**
* The mappingLocations for searching xml mapping. Only used when
* mappingLocations is empty/not explicitly specified.
* The mappingLocations for searching xml mapping.
*/
private List<String> mappingLocations = new ArrayList<>();
@@ -105,13 +105,6 @@ 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;
@@ -126,6 +119,12 @@ 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.
@@ -966,7 +965,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
@Override
public <T> Query<T> createQuery(Class<T> beanType, String eql) {
public <T> DefaultOrmQuery<T> createQuery(Class<T> beanType, String eql) {
DefaultOrmQuery<T> query = createQuery(beanType);
EqlParser.parse(eql, query);
return query;
@@ -999,6 +998,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return new DefaultDtoQuery<>(this, descriptor, sql.trim());
}
@Override
public <T> DtoQuery<T> createNamedDtoQuery(Class<T> dtoType, String namedQuery) {
DtoBeanDescriptor<T> descriptor = dtoBeanManager.getDescriptor(dtoType);
SpiRawSql rawSql = descriptor.getNamedRawSql(namedQuery);
if (rawSql != null) {
return new DefaultDtoQuery<>(this, descriptor, rawSql.getSql().getUnparsedSql());
}
throw new PersistenceException("No named query called " + namedQuery + " for bean:" + dtoType.getName());
}
@Override
public <T> DtoQuery<T> findDto(Class<T> dtoType, SpiQuery<?> ormQuery) {
@@ -0,0 +1,56 @@
package io.ebeaninternal.server.core;
import io.ebean.config.ServerConfig;
import io.ebeaninternal.xmlmapping.XmlMappingReader;
import io.ebeaninternal.xmlmapping.model.XmEbean;
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.List;
class InternalConfigXmlRead {
private static final Logger log = LoggerFactory.getLogger(InternalConfigXmlRead.class);
private final ServerConfig serverConfig;
InternalConfigXmlRead(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
}
List<XmEbean> build() {
ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
List<XmEbean> xmlEbeanList = XmlMappingReader.readByResourceName(classLoader, "ebean.xml");
List<Resource> resources = searchXmlMapping();
xmlEbeanList.addAll(XmlMappingReader.readByResourceList(resources));
return xmlEbeanList;
}
private List<Resource> searchXmlMapping() {
List<ClassPathScanner> scanners = ClassPathScanners.find(serverConfig);
List<String> mappingLocations = serverConfig.getMappingLocations();
List<Resource> 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, resourceName -> resourceName.endsWith(".xml")));
}
}
}
long searchTime = System.currentTimeMillis() - st;
log.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime);
return resourceList;
}
}
@@ -69,19 +69,23 @@ 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
@@ -134,6 +138,8 @@ public class InternalConfiguration {
private final MultiValueBind multiValueBind;
private List<XmEbean> xmlEbeanList = new ArrayList<>();
public InternalConfiguration(ClusterManager clusterManager,
SpiCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
ServerConfig serverConfig, BootupClasses bootupClasses) {
@@ -153,12 +159,20 @@ public class InternalConfiguration {
this.multiValueBind = createMultiValueBind(databasePlatform.getPlatform());
this.deployInherit = new DeployInherit(bootupClasses);
xmlEbeanList = XmlMappingReader.readByResourceName(serverConfig.getClassLoadConfig().getClassLoader(),
"ebean.xml");
List<Resource> 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);
this.beanDescriptorManager = new BeanDescriptorManager(this);
Map<String, String> asOfTableMapping = beanDescriptorManager.deploy();
Map<String, String> asOfTableMapping = beanDescriptorManager.deploy(xmlEbeanList);
Map<String, String> draftTableMap = beanDescriptorManager.getDraftTableMap();
beanDescriptorManager.scheduleBackgroundTrim();
@@ -167,6 +181,31 @@ public class InternalConfiguration {
this.cQueryEngine = new CQueryEngine(serverConfig, databasePlatform, binder, asOfTableMapping, draftTableMap);
}
private List<Resource> searchXmlMapping() {
List<ClassPathScanner> scanners = ClassPathScanners.find(serverConfig);
List<String> mappingLocations = serverConfig.getMappingLocations();
List<Resource> 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.
*/
@@ -367,12 +367,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
/**
* Deploy returning the asOfTableMap (which is required by the SQL builders).
*/
public Map<String, String> deploy() {
public Map<String, String> deploy(List<XmEbean> mappings) {
try {
createListeners();
readEntityDeploymentInitial();
readXmlMapping();
readXmlMapping(mappings);
readEmbeddedDeployment();
readEntityBeanTable();
readEntityDeploymentAssociations();
@@ -403,63 +403,15 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
}
private void readXmlMapping() {
private void readXmlMapping(List<XmEbean> mappings) {
ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
try {
ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
Enumeration<URL> resources = classLoader.getResources("ebean.xml");
List<XmEbean> mappings = new ArrayList<>();
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
try (InputStream is = url.openStream()) {
mappings.add(XmlMappingReader.read(is));
}
}
List<Resource> xmlMappingResources = searchXmlMapping();
for (Resource xmlMappingRes : xmlMappingResources) {
try (InputStream is = new FileInputStream(xmlMappingRes.getLocationOnDisk())) {
mappings.add(XmlMappingReader.read(is));
}
}
for (XmEbean mapping : mappings) {
List<XmEntity> entityDeploy = mapping.getEntity();
for (XmEntity deploy : entityDeploy) {
readEntityMapping(classLoader, deploy);
}
}
} catch (IOException e) {
throw new RuntimeException("Error reading ebean xml mapping", e);
}
}
private List<Resource> searchXmlMapping() {
List<ClassPathScanner> scanners = ClassPathScanners.find(serverConfig);
List<String> mappingLocations = serverConfig.getMappingLocations();
List<Resource> 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");
}
}));
}
for (XmEbean mapping : mappings) {
List<XmEntity> entityDeploy = mapping.getEntity();
for (XmEntity deploy : entityDeploy) {
readEntityMapping(classLoader, deploy);
}
}
long searchTime = System.currentTimeMillis() - st;
logger.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime);
return resourceList;
}
private void readEntityMapping(ClassLoader classLoader, XmEntity entityDeploy) {
@@ -1112,6 +1064,11 @@ 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);
@@ -1,7 +1,9 @@
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;
@@ -10,15 +12,25 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class DtoBeanDescriptor<T> {
private static final Map<String, String> EMPTY_NAMED_QUERY = new HashMap<>();
private static final Map<String, SpiRawSql> EMPTY_RAW_MAP = new HashMap<>();
private final Map<Object, DtoQueryPlan> plans = new ConcurrentHashMap<>();
private final Class<T> dtoType;
private final DtoMeta meta;
private Map<String, SpiRawSql> namedRawSql;
private Map<String, String> namedQuery;
DtoBeanDescriptor(Class<T> dtoType, DtoMeta meta) {
this.dtoType = dtoType;
this.meta = meta;
this.namedQuery = getNamedQuery();
this.namedRawSql = getNamedRawSql();
}
public Class<T> getType() {
@@ -42,4 +54,52 @@ public class DtoBeanDescriptor<T> {
plan.visit(visitor);
}
}
/**
* Return the named ORM query.
*/
public String getNamedQuery(String name) {
return namedQuery.get(name);
}
/**
* Return the named RawSql query.
*/
public SpiRawSql getNamedRawSql(String named) {
return namedRawSql.get(named);
}
/**
* Return the named ORM queries.
*/
public Map<String, String> getNamedQuery() {
return (namedQuery != null) ? namedQuery : EMPTY_NAMED_QUERY;
}
/**
* Add a named query.
*/
public void addNamedQuery(String name, String query) {
if (namedQuery == null) {
namedQuery = new LinkedHashMap<>();
}
namedQuery.put(name, query);
}
/**
* Return the named RawSql queries.
*/
public Map<String, SpiRawSql> getNamedRawSql() {
return (namedRawSql != null) ? namedRawSql : EMPTY_RAW_MAP;
}
/**
* Add a named RawSql from ebean.xml file.
*/
public void addRawSql(String name, SpiRawSql rawSql) {
if (namedRawSql == null) {
namedRawSql = new HashMap<>();
}
namedRawSql.put(name, rawSql);
}
}
@@ -1,16 +1,28 @@
package io.ebeaninternal.server.dto;
import io.ebean.RawSqlBuilder;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.server.type.TypeManager;
import io.ebeaninternal.xmlmapping.model.XmAliasMapping;
import io.ebeaninternal.xmlmapping.model.XmColumnMapping;
import io.ebeaninternal.xmlmapping.model.XmDto;
import io.ebeaninternal.xmlmapping.model.XmEbean;
import io.ebeaninternal.xmlmapping.model.XmNamedQuery;
import io.ebeaninternal.xmlmapping.model.XmRawSql;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages all the DTO bean descriptors.
*/
public class DtoBeanManager {
private static final Logger logger = LoggerFactory.getLogger(DtoBeanManager.class);
private final TypeManager typeManager;
private final Map<Class, DtoBeanDescriptor> descriptorMap = new ConcurrentHashMap<>();
@@ -43,4 +55,45 @@ public class DtoBeanManager {
value.visit(visitor);
}
}
public void readXmlMapping(ClassLoader classLoader, List<XmEbean> mappings) {
for (XmEbean mapping : mappings) {
List<XmDto> dtoList = mapping.getDto();
for (XmDto dto : dtoList) {
readDtoMapping(classLoader, dto);
}
}
}
private void readDtoMapping(ClassLoader classLoader, XmDto dto) {
String dtoClassName = dto.getClazz();
Class<?> dtoClass;
try {
dtoClass = Class.forName(dtoClassName, false, classLoader);
} catch (Exception e) {
logger.error("Could not load dto bean class " + dtoClassName + " for ebean xml entry");
return;
}
DtoBeanDescriptor<?> dtoBeanDescriptor = getDescriptor(dtoClass);
if (dtoBeanDescriptor == null) {
logger.error("No dto bean for ebean xml entry " + dtoClass);
} else {
for (XmRawSql sql : dto.getRawSql()) {
RawSqlBuilder builder = RawSqlBuilder.parse(sql.getQuery().getValue());
for (XmColumnMapping columnMapping : sql.getColumnMapping()) {
builder.columnMapping(columnMapping.getColumn(), columnMapping.getProperty());
}
for (XmAliasMapping aliasMapping : sql.getAliasMapping()) {
builder.tableAliasMapping(aliasMapping.getAlias(), aliasMapping.getProperty());
}
dtoBeanDescriptor.addRawSql(sql.getName(), (SpiRawSql)builder.create());
}
for (XmNamedQuery namedQuery : dto.getNamedQuery()) {
dtoBeanDescriptor.addNamedQuery(namedQuery.getName(), namedQuery.getQuery().getValue());
}
}
}
}
@@ -0,0 +1,23 @@
package io.ebeaninternal.server.dto;
import java.util.HashMap;
import java.util.Map;
/**
* Collection of named queries for a single Dto bean type.
*/
public class DtoNamedQueries {
private Map<String, String> namedRawSql = new HashMap<>();
/**
* Add the named query from deployment XML.
*/
public void addRawSql(String name, String query) {
namedRawSql.put(name, query);
}
Map<String, String> map() {
return namedRawSql;
}
}
@@ -1,11 +1,17 @@
package io.ebeaninternal.xmlmapping;
import io.ebeaninternal.xmlmapping.model.XmEbean;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.InputStream;
import org.avaje.classpath.scanner.Resource;
public class XmlMappingReader {
@@ -24,4 +30,34 @@ public class XmlMappingReader {
throw new RuntimeException(e);
}
}
public static List<XmEbean> readByResourceName(ClassLoader classLoader, String resourceName){
try {
Enumeration<URL> resources = classLoader.getResources(resourceName);
List<XmEbean> mappings = new ArrayList<>();
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
try (InputStream is = url.openStream()) {
mappings.add(XmlMappingReader.read(is));
}
}
return mappings;
} catch (IOException e) {
throw new RuntimeException("Error reading ebean xml mapping", e);
}
}
public static List<XmEbean> readByResourceList(ClassLoader classLoader, List<Resource> resourceList){
try {
List<XmEbean> mappings = new ArrayList<>();
for (Resource xmlMappingRes : resourceList) {
try (InputStream is = new FileInputStream(xmlMappingRes.getLocationOnDisk())) {
mappings.add(XmlMappingReader.read(is));
}
}
return mappings;
} catch (IOException e) {
throw new RuntimeException("Error reading ebean xml mapping", e);
}
}
}
@@ -0,0 +1,121 @@
package io.ebeaninternal.xmlmapping.model;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
* <p>
* <p>The following schema fragment specifies the expected content contained within this class.
* <p>
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/ebean}named-query" maxOccurs="unbounded"/>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/ebean}raw-sql" maxOccurs="unbounded"/>
* &lt;/sequence>
* &lt;attribute name="class" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"namedQuery",
"rawSql"
})
@XmlRootElement(name = "dto")
public class XmDto {
@XmlElement(name = "named-query", required = true)
protected List<XmNamedQuery> namedQuery;
@XmlElement(name = "raw-sql", required = true)
protected List<XmRawSql> rawSql;
@XmlAttribute(name = "class", required = true)
protected String clazz;
/**
* Gets the value of the namedQuery property.
* <p>
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the namedQuery property.
* <p>
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getNamedQuery().add(newItem);
* </pre>
* <p>
* <p>
* <p>
* Objects of the following type(s) are allowed in the list
* {@link XmNamedQuery }
*/
public List<XmNamedQuery> getNamedQuery() {
if (namedQuery == null) {
namedQuery = new ArrayList<>();
}
return this.namedQuery;
}
/**
* Gets the value of the rawSql property.
* <p>
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the rawSql property.
* <p>
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getRawSql().add(newItem);
* </pre>
* <p>
* <p>
* <p>
* Objects of the following type(s) are allowed in the list
* {@link XmRawSql }
*/
public List<XmRawSql> getRawSql() {
if (rawSql == null) {
rawSql = new ArrayList<>();
}
return this.rawSql;
}
/**
* Gets the value of the clazz property.
*
* @return possible object is
* {@link String }
*/
public String getClazz() {
return clazz;
}
/**
* Sets the value of the clazz property.
*
* @param value allowed object is
* {@link String }
*/
public void setClazz(String value) {
this.clazz = value;
}
}
@@ -1,12 +1,12 @@
package io.ebeaninternal.xmlmapping.model;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
/**
@@ -28,14 +28,18 @@ import java.util.List;
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"entity"
"entity",
"dto"
})
@XmlRootElement(name = "ebean")
public class XmEbean {
@XmlElement(required = true)
@XmlElement(required = false)
protected List<XmEntity> entity;
@XmlElement(required = false)
protected List<XmDto> dto;
/**
* Gets the value of the entity property.
* <p>
@@ -63,4 +67,11 @@ public class XmEbean {
return this.entity;
}
public List<XmDto> getDto() {
if (dto == null) {
dto = new ArrayList<>();
}
return this.dto;
}
}