/*
* #%L
* BroadleafCommerce Open Admin Platform
* %%
* Copyright (C) 2009 - 2013 Broadleaf Commerce
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.broadleafcommerce.openadmin.server.dao;
import org.apache.commons.collections4.map.LRUMap;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.money.Money;
import org.broadleafcommerce.common.persistence.EntityConfiguration;
import org.broadleafcommerce.common.presentation.AdminPresentationClass;
import org.broadleafcommerce.common.presentation.client.PersistencePerspectiveItemType;
import org.broadleafcommerce.common.presentation.client.SupportedFieldType;
import org.broadleafcommerce.common.presentation.client.VisibilityEnum;
import org.broadleafcommerce.common.util.dao.DynamicDaoHelper;
import org.broadleafcommerce.common.util.dao.DynamicDaoHelperImpl;
import org.broadleafcommerce.common.util.dao.EJB3ConfigurationDao;
import org.broadleafcommerce.openadmin.dto.BasicFieldMetadata;
import org.broadleafcommerce.openadmin.dto.ClassTree;
import org.broadleafcommerce.openadmin.dto.FieldMetadata;
import org.broadleafcommerce.openadmin.dto.ForeignKey;
import org.broadleafcommerce.openadmin.dto.MergedPropertyType;
import org.broadleafcommerce.openadmin.dto.PersistencePerspective;
import org.broadleafcommerce.openadmin.server.dao.provider.metadata.FieldMetadataProvider;
import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.AddMetadataFromFieldTypeRequest;
import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.LateStageAddMetadataRequest;
import org.broadleafcommerce.openadmin.server.service.AppConfigurationService;
import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager;
import org.broadleafcommerce.openadmin.server.service.persistence.validation.FieldNamePropertyValidator;
import org.broadleafcommerce.openadmin.server.service.type.FieldProviderResponse;
import org.hibernate.Criteria;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManager;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.type.ComponentType;
import org.hibernate.type.Type;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
/**
*
* @author jfischer
*
*/
@Component("blDynamicEntityDao")
@Scope("prototype")
public class DynamicEntityDaoImpl implements DynamicEntityDao, ApplicationContextAware {
private static final Log LOG = LogFactory.getLog(DynamicEntityDaoImpl.class);
protected static final Map<String,Map<String, FieldMetadata>> METADATA_CACHE = new LRUMap<String, Map<String, FieldMetadata>>(1000);
/*
* This is the same as POLYMORPHIC_ENTITY_CACHE, except that it does not contain classes that are abstract or have been marked for exclusion
* from polymorphism
*/
protected EntityManager standardEntityManager;
@Resource(name="blMetadata")
protected Metadata metadata;
@Resource(name="blEJB3ConfigurationDao")
protected EJB3ConfigurationDao ejb3ConfigurationDao;
@Resource(name="blEntityConfiguration")
protected EntityConfiguration entityConfiguration;
@Resource(name="blMetadataProviders")
protected List<FieldMetadataProvider> fieldMetadataProviders = new ArrayList<FieldMetadataProvider>();
@Resource(name= "blDefaultFieldMetadataProvider")
protected FieldMetadataProvider defaultFieldMetadataProvider;
@Resource(name="blAppConfigurationRemoteService")
protected AppConfigurationService appConfigurationRemoteService;
protected DynamicDaoHelper dynamicDaoHelper = new DynamicDaoHelperImpl();
@Value("${cache.entity.dao.metadata.ttl}")
protected int cacheEntityMetaDataTtl;
protected long lastCacheFlushTime = System.currentTimeMillis();
protected ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Criteria createCriteria(Class<?> entityClass) {
return ((HibernateEntityManager) getStandardEntityManager()).getSession().createCriteria(entityClass);
}
@Override
public <T> T persist(T entity) {
standardEntityManager.persist(entity);
standardEntityManager.flush();
return entity;
}
@Override
public Object find(Class<?> entityClass, Object key) {
return standardEntityManager.find(entityClass, key);
}
@Override
public <T> T merge(T entity) {
T response = standardEntityManager.merge(entity);
standardEntityManager.flush();
return response;
}
@Override
public void flush() {
standardEntityManager.flush();
}
@Override
public void detach(Serializable entity) {
standardEntityManager.detach(entity);
}
@Override
public void refresh(Serializable entity) {
standardEntityManager.refresh(entity);
}
@Override
public Serializable retrieve(Class<?> entityClass, Object primaryKey) {
return (Serializable) standardEntityManager.find(entityClass, primaryKey);
}
@Override
public void remove(Serializable entity) {
standardEntityManager.remove(entity);
standardEntityManager.flush();
}
@Override
public void clear() {
standardEntityManager.clear();
}
@Override
public PersistentClass getPersistentClass(String targetClassName) {
return ejb3ConfigurationDao.getConfiguration().getClassMapping(targetClassName);
}
@Override
public boolean useCache() {
if (cacheEntityMetaDataTtl < 0) {
return true;
}
if (cacheEntityMetaDataTtl == 0) {
return false;
} else {
if ((System.currentTimeMillis() - lastCacheFlushTime) > cacheEntityMetaDataTtl) {
lastCacheFlushTime = System.currentTimeMillis();
METADATA_CACHE.clear();
DynamicDaoHelperImpl.POLYMORPHIC_ENTITY_CACHE.clear();
DynamicDaoHelperImpl.POLYMORPHIC_ENTITY_CACHE_WO_EXCLUSIONS.clear();
return true; // cache is empty
} else {
return true;
}
}
}
@Override
public Class<?>[] getAllPolymorphicEntitiesFromCeiling(Class<?> ceilingClass) {
return getAllPolymorphicEntitiesFromCeiling(ceilingClass, true);
}
@Override
public Class<?>[] getAllPolymorphicEntitiesFromCeiling(Class<?> ceilingClass, boolean includeUnqualifiedPolymorphicEntities) {
return dynamicDaoHelper.getAllPolymorphicEntitiesFromCeiling(ceilingClass, getSessionFactory(),
includeUnqualifiedPolymorphicEntities, useCache());
}
@Override
public Class<?>[] getUpDownInheritance(Class<?> testClass) {
return dynamicDaoHelper.getUpDownInheritance(testClass, getSessionFactory(), true, useCache(), ejb3ConfigurationDao);
}
public Class<?>[] sortEntities(Class<?> ceilingClass, List<Class<?>> entities) {
return dynamicDaoHelper.sortEntities(ceilingClass, entities);
}
protected void addClassToTree(Class<?> clazz, ClassTree tree) {
Class<?> testClass;
try {
testClass = Class.forName(tree.getFullyQualifiedClassname());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (clazz.equals(testClass)) {
return;
}
if (clazz.getSuperclass().equals(testClass)) {
ClassTree myTree = new ClassTree(clazz.getName(), isExcludeClassFromPolymorphism(clazz));
createClassTreeFromAnnotation(clazz, myTree);
tree.setChildren((ClassTree[]) ArrayUtils.add(tree.getChildren(), myTree));
} else {
for (ClassTree child : tree.getChildren()) {
addClassToTree(clazz, child);
}
}
}
protected void createClassTreeFromAnnotation(Class<?> clazz, ClassTree myTree) {
AdminPresentationClass classPresentation = clazz.getAnnotation(AdminPresentationClass.class);
if (classPresentation != null) {
String friendlyName = classPresentation.friendlyName();
if (!StringUtils.isEmpty(friendlyName)) {
myTree.setFriendlyName(friendlyName);
}
}
}
@Override
public ClassTree getClassTree(Class<?>[] polymorphicClasses) {
String ceilingClass = null;
for (Class<?> clazz : polymorphicClasses) {
AdminPresentationClass classPresentation = clazz.getAnnotation(AdminPresentationClass.class);
if (classPresentation != null) {
String ceilingEntity = classPresentation.ceilingDisplayEntity();
if (!StringUtils.isEmpty(ceilingEntity)) {
ceilingClass = ceilingEntity;
break;
}
}
}
if (ceilingClass != null) {
int pos = -1;
int j = 0;
for (Class<?> clazz : polymorphicClasses) {
if (clazz.getName().equals(ceilingClass)) {
pos = j;
break;
}
j++;
}
if (pos >= 0) {
Class<?>[] temp = new Class<?>[pos + 1];
System.arraycopy(polymorphicClasses, 0, temp, 0, j + 1);
polymorphicClasses = temp;
}
}
ClassTree classTree = null;
if (!ArrayUtils.isEmpty(polymorphicClasses)) {
Class<?> topClass = polymorphicClasses[polymorphicClasses.length-1];
classTree = new ClassTree(topClass.getName(), isExcludeClassFromPolymorphism(topClass));
createClassTreeFromAnnotation(topClass, classTree);
for (int j=polymorphicClasses.length-1; j >= 0; j--) {
addClassToTree(polymorphicClasses[j], classTree);
}
classTree.finalizeStructure(1);
}
return classTree;
}
@Override
public ClassTree getClassTreeFromCeiling(Class<?> ceilingClass) {
Class<?>[] sortedEntities = getAllPolymorphicEntitiesFromCeiling(ceilingClass);
return getClassTree(sortedEntities);
}
@Override
public Map<String, FieldMetadata> getSimpleMergedProperties(String entityName, PersistencePerspective persistencePerspective) {
Class<?>[] entityClasses;
try {
entityClasses = getAllPolymorphicEntitiesFromCeiling(Class.forName(entityName));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (!ArrayUtils.isEmpty(entityClasses)) {
return getMergedProperties(
entityName,
entityClasses,
(ForeignKey) persistencePerspective.getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.FOREIGNKEY),
persistencePerspective.getAdditionalNonPersistentProperties(),
persistencePerspective.getAdditionalForeignKeys(),
MergedPropertyType.PRIMARY,
persistencePerspective.getPopulateToOneFields(),
persistencePerspective.getIncludeFields(),
persistencePerspective.getExcludeFields(),
persistencePerspective.getConfigurationKey(),
""
);
} else {
Map<String, FieldMetadata> mergedProperties = new HashMap<String, FieldMetadata>();
Class<?> targetClass;
try {
targetClass = Class.forName(entityName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
Map<String, FieldMetadata> attributesMap = metadata.getFieldPresentationAttributes(null, targetClass, this, "");
for (String property : attributesMap.keySet()) {
FieldMetadata presentationAttribute = attributesMap.get(property);
if (!presentationAttribute.getExcluded()) {
Field field = FieldManager.getSingleField(targetClass, property);
if (!Modifier.isStatic(field.getModifiers())) {
boolean handled = false;
for (FieldMetadataProvider provider : fieldMetadataProviders) {
FieldProviderResponse response = provider.addMetadataFromFieldType(
new AddMetadataFromFieldTypeRequest(field, targetClass, null, new ForeignKey[]{},
MergedPropertyType.PRIMARY, null, null, "",
property, null, false, 0, attributesMap, presentationAttribute,
((BasicFieldMetadata) presentationAttribute).getExplicitFieldType(), field.getType(), this),
mergedProperties);
if (FieldProviderResponse.NOT_HANDLED != response) {
handled = true;
}
if (FieldProviderResponse.HANDLED_BREAK == response) {
break;
}
}
if (!handled) {
//this provider is not included in the provider list on purpose - it is designed to handle basic
//AdminPresentation fields, and those fields not admin presentation annotated at all
defaultFieldMetadataProvider.addMetadataFromFieldType(
new AddMetadataFromFieldTypeRequest(field, targetClass, null, new ForeignKey[]{},
MergedPropertyType.PRIMARY, null, null, "", property,
null, false, 0, attributesMap, presentationAttribute, ((BasicFieldMetadata) presentationAttribute).getExplicitFieldType(),
field.getType(), this), mergedProperties);
}
}
}
}
return mergedProperties;
}
}
@Override
public Map<String, FieldMetadata> getMergedProperties(@Nonnull Class<?> cls) {
Class<?>[] polymorphicTypes = getAllPolymorphicEntitiesFromCeiling(cls);
return getMergedProperties(
cls.getName(),
polymorphicTypes,
null,
new String[] {},
new ForeignKey[] {},
MergedPropertyType.PRIMARY,
true,
new String[] {},
new String[] {},
null,
""
);
}
@Override
public Map<String, FieldMetadata> getMergedProperties(
String ceilingEntityFullyQualifiedClassname,
Class<?>[] entities,
ForeignKey foreignField,
String[] additionalNonPersistentProperties,
ForeignKey[] additionalForeignFields,
MergedPropertyType mergedPropertyType,
Boolean populateManyToOneFields,
String[] includeFields,
String[] excludeFields,
String configurationKey,
String prefix
) {
Map<String, FieldMetadata> mergedProperties = getMergedPropertiesRecursively(
ceilingEntityFullyQualifiedClassname,
entities,
foreignField,
additionalNonPersistentProperties,
additionalForeignFields,
mergedPropertyType,
populateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
new ArrayList<Class<?>>(),
prefix,
false
);
final List<String> removeKeys = new ArrayList<String>();
for (final String key : mergedProperties.keySet()) {
if (mergedProperties.get(key).getExcluded() != null && mergedProperties.get(key).getExcluded()) {
removeKeys.add(key);
}
}
for (String removeKey : removeKeys) {
mergedProperties.remove(removeKey);
}
// Allow field metadata providers to contribute additional fields here. These latestage handlers take place
// after any cached lookups occur, and are ideal for adding in dynamic properties that are not globally cacheable
// like properties gleaned from reflection typically are.
Set<String> keys = new HashSet<String>(mergedProperties.keySet());
for (Class<?> targetClass : entities) {
for (String key : keys) {
LateStageAddMetadataRequest amr = new LateStageAddMetadataRequest(key, null, targetClass, this, "");
boolean foundOneOrMoreHandlers = false;
for (FieldMetadataProvider fieldMetadataProvider : fieldMetadataProviders) {
FieldProviderResponse response = fieldMetadataProvider.lateStageAddMetadata(amr, mergedProperties);
if (FieldProviderResponse.NOT_HANDLED != response) {
foundOneOrMoreHandlers = true;
}
if (FieldProviderResponse.HANDLED_BREAK == response) {
break;
}
}
if (!foundOneOrMoreHandlers) {
defaultFieldMetadataProvider.lateStageAddMetadata(amr, mergedProperties);
}
}
}
return mergedProperties;
}
protected Map<String, FieldMetadata> getMergedPropertiesRecursively(
final String ceilingEntityFullyQualifiedClassname,
final Class<?>[] entities,
final ForeignKey foreignField,
final String[] additionalNonPersistentProperties,
final ForeignKey[] additionalForeignFields,
final MergedPropertyType mergedPropertyType,
final Boolean populateManyToOneFields,
final String[] includeFields,
final String[] excludeFields,
final String configurationKey,
final List<Class<?>> parentClasses,
final String prefix,
final Boolean isParentExcluded
) {
PropertyBuilder propertyBuilder = new PropertyBuilder() {
@Override
public Map<String, FieldMetadata> execute(Boolean overridePopulateManyToOne) {
Map<String, FieldMetadata> mergedProperties = new HashMap<String, FieldMetadata>();
Boolean classAnnotatedPopulateManyToOneFields;
if (overridePopulateManyToOne != null) {
classAnnotatedPopulateManyToOneFields = overridePopulateManyToOne;
} else {
classAnnotatedPopulateManyToOneFields = populateManyToOneFields;
}
buildPropertiesFromPolymorphicEntities(
entities,
foreignField,
additionalNonPersistentProperties,
additionalForeignFields,
mergedPropertyType,
classAnnotatedPopulateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
ceilingEntityFullyQualifiedClassname,
mergedProperties,
parentClasses,
prefix,
isParentExcluded
);
return mergedProperties;
}
};
Map<String, FieldMetadata> mergedProperties = metadata.overrideMetadata(entities, propertyBuilder, prefix, isParentExcluded, ceilingEntityFullyQualifiedClassname, configurationKey, this);
applyIncludesAndExcludes(includeFields, excludeFields, prefix, isParentExcluded, mergedProperties);
applyForeignKeyPrecedence(foreignField, additionalForeignFields, mergedProperties);
return mergedProperties;
}
protected void applyForeignKeyPrecedence(ForeignKey foreignField, ForeignKey[] additionalForeignFields, Map<String, FieldMetadata> mergedProperties) {
for (String key : mergedProperties.keySet()) {
boolean isForeign = false;
if (foreignField != null) {
isForeign = foreignField.getManyToField().equals(key);
}
if (!isForeign && !ArrayUtils.isEmpty(additionalForeignFields)) {
for (ForeignKey foreignKey : additionalForeignFields) {
isForeign = foreignKey.getManyToField().equals(key);
if (isForeign) {
break;
}
}
}
if (isForeign) {
FieldMetadata metadata = mergedProperties.get(key);
metadata.setExcluded(false);
}
}
}
protected void applyIncludesAndExcludes(String[] includeFields, String[] excludeFields, String prefix, Boolean isParentExcluded, Map<String, FieldMetadata> mergedProperties) {
//check includes
if (!ArrayUtils.isEmpty(includeFields)) {
for (String include : includeFields) {
for (String key : mergedProperties.keySet()) {
String testKey = prefix + key;
if (!(testKey.startsWith(include + ".") || testKey.equals(include))) {
FieldMetadata metadata = mergedProperties.get(key);
LOG.debug("applyIncludesAndExcludes:Excluding " + key + " because this field did not appear in the explicit includeFields list");
metadata.setExcluded(true);
} else {
FieldMetadata metadata = mergedProperties.get(key);
if (!isParentExcluded) {
LOG.debug("applyIncludesAndExcludes:Showing " + key + " because this field appears in the explicit includeFields list");
metadata.setExcluded(false);
}
}
}
}
} else if (!ArrayUtils.isEmpty(excludeFields)) {
//check excludes
for (String exclude : excludeFields) {
for (String key : mergedProperties.keySet()) {
String testKey = prefix + key;
if (testKey.startsWith(exclude + ".") || testKey.equals(exclude)) {
FieldMetadata metadata = mergedProperties.get(key);
LOG.debug("applyIncludesAndExcludes:Excluding " + key + " because this field appears in the explicit excludeFields list");
metadata.setExcluded(true);
} else {
FieldMetadata metadata = mergedProperties.get(key);
if (!isParentExcluded) {
LOG.debug("applyIncludesAndExcludes:Showing " + key + " because this field did not appear in the explicit excludeFields list");
metadata.setExcluded(false);
}
}
}
}
}
}
protected String pad(String s, int length, char pad) {
StringBuilder buffer = new StringBuilder(s);
while (buffer.length() < length) {
buffer.insert(0, pad);
}
return buffer.toString();
}
protected String getCacheKey(ForeignKey foreignField, String[] additionalNonPersistentProperties, ForeignKey[] additionalForeignFields, MergedPropertyType mergedPropertyType, Boolean populateManyToOneFields, Class<?> clazz, String configurationKey, Boolean isParentExcluded) {
StringBuilder sb = new StringBuilder(150);
sb.append(clazz.hashCode());
sb.append(foreignField==null?"":foreignField.toString());
sb.append(configurationKey);
sb.append(isParentExcluded);
if (additionalNonPersistentProperties != null) {
for (String prop : additionalNonPersistentProperties) {
sb.append(prop);
}
}
if (additionalForeignFields != null) {
for (ForeignKey key : additionalForeignFields) {
sb.append(key.toString());
}
}
sb.append(mergedPropertyType);
sb.append(populateManyToOneFields);
String digest;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(sb.toString().getBytes());
BigInteger number = new BigInteger(1,messageDigest);
digest = number.toString(16);
} catch(NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return pad(digest, 32, '0');
}
protected void buildPropertiesFromPolymorphicEntities(
Class<?>[] entities,
ForeignKey foreignField,
String[] additionalNonPersistentProperties,
ForeignKey[] additionalForeignFields,
MergedPropertyType mergedPropertyType,
Boolean populateManyToOneFields,
String[] includeFields,
String[] excludeFields,
String configurationKey,
String ceilingEntityFullyQualifiedClassname,
Map<String, FieldMetadata> mergedProperties,
List<Class<?>> parentClasses,
String prefix,
Boolean isParentExcluded
) {
for (Class<?> clazz : entities) {
String cacheKey = getCacheKey(foreignField, additionalNonPersistentProperties, additionalForeignFields, mergedPropertyType, populateManyToOneFields, clazz, configurationKey, isParentExcluded);
Map<String, FieldMetadata> cacheData = null;
synchronized(DynamicDaoHelperImpl.LOCK_OBJECT) {
if (useCache()) {
cacheData = METADATA_CACHE.get(cacheKey);
}
if (cacheData == null) {
Map<String, FieldMetadata> props = getPropertiesForEntityClass(
clazz,
foreignField,
additionalNonPersistentProperties,
additionalForeignFields,
mergedPropertyType,
populateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
ceilingEntityFullyQualifiedClassname,
parentClasses,
prefix,
isParentExcluded
);
//first check all the properties currently in there to see if my entity inherits from them
for (Class<?> clazz2 : entities) {
if (!clazz2.getName().equals(clazz.getName())) {
for (Map.Entry<String, FieldMetadata> entry : props.entrySet()) {
FieldMetadata metadata = entry.getValue();
try {
if (Class.forName(metadata.getInheritedFromType()).isAssignableFrom(clazz2)) {
String[] both = (String[]) ArrayUtils.addAll(metadata.getAvailableToTypes(), new String[]{clazz2.getName()});
metadata.setAvailableToTypes(both);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
METADATA_CACHE.put(cacheKey, props);
cacheData = props;
}
}
//clone the metadata before passing to the system
Map<String, FieldMetadata> clonedCache = new HashMap<String, FieldMetadata>(cacheData.size());
for (Map.Entry<String, FieldMetadata> entry : cacheData.entrySet()) {
clonedCache.put(entry.getKey(), entry.getValue().cloneFieldMetadata());
}
mergedProperties.putAll(clonedCache);
}
}
@Override
public Field[] getAllFields(Class<?> targetClass) {
Field[] allFields = new Field[]{};
boolean eof = false;
Class<?> currentClass = targetClass;
while (!eof) {
Field[] fields = currentClass.getDeclaredFields();
allFields = (Field[]) ArrayUtils.addAll(allFields, fields);
if (currentClass.getSuperclass() != null) {
currentClass = currentClass.getSuperclass();
} else {
eof = true;
}
}
return allFields;
}
@Override
public Map<String, FieldMetadata> getPropertiesForPrimitiveClass(
String propertyName,
String friendlyPropertyName,
Class<?> targetClass,
Class<?> parentClass,
MergedPropertyType mergedPropertyType
) {
Map<String, FieldMetadata> fields = new HashMap<String, FieldMetadata>();
BasicFieldMetadata presentationAttribute = new BasicFieldMetadata();
presentationAttribute.setFriendlyName(friendlyPropertyName);
if (String.class.isAssignableFrom(targetClass)) {
presentationAttribute.setExplicitFieldType(SupportedFieldType.STRING);
presentationAttribute.setVisibility(VisibilityEnum.VISIBLE_ALL);
fields.put(propertyName, metadata.getFieldMetadata("", propertyName, null, SupportedFieldType.STRING, null, parentClass, presentationAttribute, mergedPropertyType, this));
} else if (Boolean.class.isAssignableFrom(targetClass)) {
presentationAttribute.setExplicitFieldType(SupportedFieldType.BOOLEAN);
presentationAttribute.setVisibility(VisibilityEnum.VISIBLE_ALL);
fields.put(propertyName, metadata.getFieldMetadata("", propertyName, null, SupportedFieldType.BOOLEAN, null, parentClass, presentationAttribute, mergedPropertyType, this));
} else if (Date.class.isAssignableFrom(targetClass)) {
presentationAttribute.setExplicitFieldType(SupportedFieldType.DATE);
presentationAttribute.setVisibility(VisibilityEnum.VISIBLE_ALL);
fields.put(propertyName, metadata.getFieldMetadata("", propertyName, null, SupportedFieldType.DATE, null, parentClass, presentationAttribute, mergedPropertyType, this));
} else if (Money.class.isAssignableFrom(targetClass)) {
presentationAttribute.setExplicitFieldType(SupportedFieldType.MONEY);
presentationAttribute.setVisibility(VisibilityEnum.VISIBLE_ALL);
fields.put(propertyName, metadata.getFieldMetadata("", propertyName, null, SupportedFieldType.MONEY, null, parentClass, presentationAttribute, mergedPropertyType, this));
} else if (
Byte.class.isAssignableFrom(targetClass) ||
Integer.class.isAssignableFrom(targetClass) ||
Long.class.isAssignableFrom(targetClass) ||
Short.class.isAssignableFrom(targetClass)
) {
presentationAttribute.setExplicitFieldType(SupportedFieldType.INTEGER);
presentationAttribute.setVisibility(VisibilityEnum.VISIBLE_ALL);
fields.put(propertyName, metadata.getFieldMetadata("", propertyName, null, SupportedFieldType.INTEGER, null, parentClass, presentationAttribute, mergedPropertyType, this));
} else if (
Double.class.isAssignableFrom(targetClass) ||
BigDecimal.class.isAssignableFrom(targetClass)
) {
presentationAttribute.setExplicitFieldType(SupportedFieldType.DECIMAL);
presentationAttribute.setVisibility(VisibilityEnum.VISIBLE_ALL);
fields.put(propertyName, metadata.getFieldMetadata("", propertyName, null, SupportedFieldType.DECIMAL, null, parentClass, presentationAttribute, mergedPropertyType, this));
}
((BasicFieldMetadata) fields.get(propertyName)).setLength(255);
((BasicFieldMetadata) fields.get(propertyName)).setForeignKeyCollection(false);
((BasicFieldMetadata) fields.get(propertyName)).setRequired(true);
((BasicFieldMetadata) fields.get(propertyName)).setUnique(true);
((BasicFieldMetadata) fields.get(propertyName)).setScale(100);
((BasicFieldMetadata) fields.get(propertyName)).setPrecision(100);
return fields;
}
@Override
public SessionFactory getSessionFactory() {
return dynamicDaoHelper.getSessionFactory((HibernateEntityManager) standardEntityManager);
}
@Override
public Map<String, Object> getIdMetadata(Class<?> entityClass) {
return dynamicDaoHelper.getIdMetadata(entityClass, (HibernateEntityManager) standardEntityManager);
}
@Override
public List<String> getPropertyNames(Class<?> entityClass) {
return dynamicDaoHelper.getPropertyNames(entityClass, (HibernateEntityManager) standardEntityManager);
}
@Override
public List<Type> getPropertyTypes(Class<?> entityClass) {
return dynamicDaoHelper.getPropertyTypes(entityClass, (HibernateEntityManager) standardEntityManager);
}
protected Map<String, FieldMetadata> getPropertiesForEntityClass(
Class<?> targetClass,
ForeignKey foreignField,
String[] additionalNonPersistentProperties,
ForeignKey[] additionalForeignFields,
MergedPropertyType mergedPropertyType,
Boolean populateManyToOneFields,
String[] includeFields,
String[] excludeFields,
String configurationKey,
String ceilingEntityFullyQualifiedClassname,
List<Class<?>> parentClasses,
String prefix,
Boolean isParentExcluded
) {
Map<String, FieldMetadata> presentationAttributes = metadata.getFieldPresentationAttributes(null, targetClass, this, "");
if (isParentExcluded) {
for (String key : presentationAttributes.keySet()) {
LOG.debug("getPropertiesForEntityClass:Excluding " + key + " because parent is excluded.");
presentationAttributes.get(key).setExcluded(true);
}
}
Map idMetadata = getIdMetadata(targetClass);
Map<String, FieldMetadata> fields = new HashMap<String, FieldMetadata>();
String idProperty = (String) idMetadata.get("name");
List<String> propertyNames = getPropertyNames(targetClass);
propertyNames.add(idProperty);
Type idType = (Type) idMetadata.get("type");
List<Type> propertyTypes = getPropertyTypes(targetClass);
propertyTypes.add(idType);
PersistentClass persistentClass = getPersistentClass(targetClass.getName());
Iterator testIter = persistentClass.getPropertyIterator();
List<Property> propertyList = new ArrayList<Property>();
//check the properties for problems
while(testIter.hasNext()) {
Property property = (Property) testIter.next();
if (property.getName().contains(".")) {
throw new IllegalArgumentException("Properties from entities that utilize a period character ('.') in their name are incompatible with this system. The property name in question is: (" + property.getName() + ") from the class: (" + targetClass.getName() + ")");
}
propertyList.add(property);
}
buildProperties(
targetClass,
foreignField,
additionalForeignFields,
additionalNonPersistentProperties,
mergedPropertyType,
presentationAttributes,
propertyList,
fields,
propertyNames,
propertyTypes,
idProperty,
populateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
ceilingEntityFullyQualifiedClassname,
parentClasses,
prefix,
isParentExcluded,
false
);
BasicFieldMetadata presentationAttribute = new BasicFieldMetadata();
presentationAttribute.setExplicitFieldType(SupportedFieldType.STRING);
presentationAttribute.setVisibility(VisibilityEnum.HIDDEN_ALL);
if (!ArrayUtils.isEmpty(additionalNonPersistentProperties)) {
Class<?>[] entities = getAllPolymorphicEntitiesFromCeiling(targetClass);
for (String additionalNonPersistentProperty : additionalNonPersistentProperties) {
if (StringUtils.isEmpty(prefix) || (!StringUtils.isEmpty(prefix) && additionalNonPersistentProperty.startsWith(prefix))) {
String myAdditionalNonPersistentProperty = additionalNonPersistentProperty;
//get final property if this is a dot delimited property
int finalDotPos = additionalNonPersistentProperty.lastIndexOf('.');
if (finalDotPos >= 0) {
myAdditionalNonPersistentProperty = myAdditionalNonPersistentProperty.substring(finalDotPos + 1, myAdditionalNonPersistentProperty.length());
}
//check all the polymorphic types on this target class to see if the end property exists
Field testField = null;
Method testMethod = null;
for (Class<?> clazz : entities) {
try {
testMethod = clazz.getMethod(myAdditionalNonPersistentProperty);
if (testMethod != null) {
break;
}
} catch (NoSuchMethodException e) {
//do nothing - method does not exist
}
testField = getFieldManager().getField(clazz, myAdditionalNonPersistentProperty);
if (testField != null) {
break;
}
}
//if the property exists, add it to the metadata for this class
if (testField != null || testMethod != null) {
fields.put(additionalNonPersistentProperty, metadata.getFieldMetadata(prefix, additionalNonPersistentProperty, propertyList, SupportedFieldType.STRING, null, targetClass, presentationAttribute, mergedPropertyType, this));
}
}
}
}
return fields;
}
protected void buildProperties(
Class<?> targetClass,
ForeignKey foreignField,
ForeignKey[] additionalForeignFields,
String[] additionalNonPersistentProperties,
MergedPropertyType mergedPropertyType,
Map<String, FieldMetadata> presentationAttributes,
List<Property> componentProperties,
Map<String, FieldMetadata> fields,
List<String> propertyNames,
List<Type> propertyTypes,
String idProperty,
Boolean populateManyToOneFields,
String[] includeFields,
String[] excludeFields,
String configurationKey,
String ceilingEntityFullyQualifiedClassname,
List<Class<?>> parentClasses,
String prefix,
Boolean isParentExcluded,
Boolean isComponentPrefix
) {
int j = 0;
Comparator<String> propertyComparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//check for property name equality and for map field properties
if (o1.equals(o2) || o1.startsWith(o2 + FieldManager.MAPFIELDSEPARATOR) || o2.startsWith(o1 + FieldManager.MAPFIELDSEPARATOR)) {
return 0;
}
return o1.compareTo(o2);
}
};
List<String> presentationKeyList = new ArrayList<String>(presentationAttributes.keySet());
Collections.sort(presentationKeyList);
for (String propertyName : propertyNames) {
final Type type = propertyTypes.get(j);
boolean isPropertyForeignKey = testForeignProperty(foreignField, prefix, propertyName);
int additionalForeignKeyIndexPosition = findAdditionalForeignKeyIndex(additionalForeignFields, prefix, propertyName);
j++;
Field myField = getFieldManager().getField(targetClass, propertyName);
if (myField == null) {
//try to get the field with the prefix - needed for advanced collections that appear in @Embedded classes
myField = getFieldManager().getField(targetClass, prefix + propertyName);
}
if (
!type.isAnyType() && !type.isCollectionType() ||
isPropertyForeignKey ||
additionalForeignKeyIndexPosition >= 0 ||
Collections.binarySearch(presentationKeyList, propertyName, propertyComparator) >= 0
) {
if (myField != null) {
boolean handled = false;
for (FieldMetadataProvider provider : fieldMetadataProviders) {
FieldMetadata presentationAttribute = presentationAttributes.get(propertyName);
if (presentationAttribute != null) {
setExcludedBasedOnShowIfProperty(presentationAttribute);
}
FieldProviderResponse response = provider.addMetadataFromFieldType(
new AddMetadataFromFieldTypeRequest(myField, targetClass, foreignField, additionalForeignFields,
mergedPropertyType, componentProperties, idProperty, prefix,
propertyName, type, isPropertyForeignKey, additionalForeignKeyIndexPosition,
presentationAttributes, presentationAttribute, null, type.getReturnedClass(), this), fields);
if (FieldProviderResponse.NOT_HANDLED != response) {
handled = true;
}
if (FieldProviderResponse.HANDLED_BREAK == response) {
break;
}
}
if (!handled) {
buildBasicProperty(myField, targetClass, foreignField, additionalForeignFields,
additionalNonPersistentProperties, mergedPropertyType, presentationAttributes,
componentProperties, fields, idProperty, populateManyToOneFields, includeFields,
excludeFields, configurationKey, ceilingEntityFullyQualifiedClassname, parentClasses,
prefix, isParentExcluded, propertyName, type, isPropertyForeignKey, additionalForeignKeyIndexPosition, isComponentPrefix);
}
}
}
}
}
public Boolean testPropertyInclusion(FieldMetadata presentationAttribute) {
setExcludedBasedOnShowIfProperty(presentationAttribute);
return !(presentationAttribute != null && ((presentationAttribute.getExcluded() != null && presentationAttribute.getExcluded()) || (presentationAttribute.getChildrenExcluded() != null && presentationAttribute.getChildrenExcluded())));
}
protected boolean setExcludedBasedOnShowIfProperty(FieldMetadata fieldMetadata) {
if(fieldMetadata != null && fieldMetadata.getShowIfProperty()!=null && !fieldMetadata.getShowIfProperty().equals("")
&& appConfigurationRemoteService.getBooleanPropertyValue(fieldMetadata.getShowIfProperty())!=null
&& !appConfigurationRemoteService.getBooleanPropertyValue(fieldMetadata.getShowIfProperty())
) {
//do not include this in the display if it returns false.
fieldMetadata.setExcluded(true);
return false;
}
return true;
}
protected Boolean testPropertyRecursion(String prefix, List<Class<?>> parentClasses, String propertyName, Class<?> targetClass,
String ceilingEntityFullyQualifiedClassname, Boolean isComponentPrefix) {
Boolean includeField = true;
//don't want to shun a self-referencing property in an @Embeddable
boolean shouldTest = !StringUtils.isEmpty(prefix) && (!isComponentPrefix || prefix.split("\\.").length > 1);
if (shouldTest) {
Field testField = getFieldManager().getField(targetClass, propertyName);
if (testField == null) {
Class<?>[] entities;
try {
entities = getAllPolymorphicEntitiesFromCeiling(Class.forName(ceilingEntityFullyQualifiedClassname));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
for (Class<?> clazz : entities) {
testField = getFieldManager().getField(clazz, propertyName);
if (testField != null) {
break;
}
}
String testProperty = prefix + propertyName;
if (testField == null) {
testField = getFieldManager().getField(targetClass, testProperty);
}
if (testField == null) {
for (Class<?> clazz : entities) {
testField = getFieldManager().getField(clazz, testProperty);
if (testField != null) {
break;
}
}
}
}
if (testField != null) {
Class<?> testType = testField.getType();
for (Class<?> parentClass : parentClasses) {
if (parentClass.isAssignableFrom(testType) || testType.isAssignableFrom(parentClass)) {
includeField = false;
break;
}
}
if (includeField && (targetClass.isAssignableFrom(testType) || testType.isAssignableFrom(targetClass))) {
includeField = false;
}
}
}
return includeField;
}
protected void buildBasicProperty(
Field field,
Class<?> targetClass,
ForeignKey foreignField,
ForeignKey[] additionalForeignFields,
String[] additionalNonPersistentProperties,
MergedPropertyType mergedPropertyType,
Map<String, FieldMetadata> presentationAttributes,
List<Property> componentProperties,
Map<String, FieldMetadata> fields,
String idProperty,
Boolean populateManyToOneFields,
String[] includeFields,
String[] excludeFields,
String configurationKey,
String ceilingEntityFullyQualifiedClassname,
List<Class<?>> parentClasses,
String prefix,
Boolean isParentExcluded,
String propertyName,
Type type,
boolean propertyForeignKey,
int additionalForeignKeyIndexPosition,
Boolean isComponentPrefix) {
FieldMetadata presentationAttribute = presentationAttributes.get(propertyName);
Boolean amIExcluded = isParentExcluded || !testPropertyInclusion(presentationAttribute);
Boolean includeField = testPropertyRecursion(prefix, parentClasses, propertyName, targetClass,
ceilingEntityFullyQualifiedClassname, isComponentPrefix);
SupportedFieldType explicitType = null;
if (presentationAttribute != null && presentationAttribute instanceof BasicFieldMetadata) {
explicitType = ((BasicFieldMetadata) presentationAttribute).getExplicitFieldType();
}
Class<?> returnedClass = type.getReturnedClass();
checkProp: {
if (type.isComponentType() && includeField) {
buildComponentProperties(
targetClass,
foreignField,
additionalForeignFields,
additionalNonPersistentProperties,
mergedPropertyType,
fields,
idProperty,
populateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
ceilingEntityFullyQualifiedClassname,
propertyName,
type,
returnedClass,
parentClasses,
amIExcluded,
prefix
);
break checkProp;
}
/*
* Currently we do not support ManyToOne fields whose class type is the same
* as the target type, since this forms an infinite loop and will cause a stack overflow.
*/
if (
type.isEntityType() &&
!returnedClass.isAssignableFrom(targetClass) &&
populateManyToOneFields &&
includeField
) {
buildEntityProperties(
fields,
foreignField,
additionalForeignFields,
additionalNonPersistentProperties,
populateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
ceilingEntityFullyQualifiedClassname,
propertyName,
returnedClass,
targetClass,
parentClasses,
prefix,
amIExcluded
);
break checkProp;
}
}
//Don't include this property if it failed manyToOne inclusion and is not a specified foreign key
if (includeField || propertyForeignKey || additionalForeignKeyIndexPosition >= 0) {
defaultFieldMetadataProvider.addMetadataFromFieldType(
new AddMetadataFromFieldTypeRequest(field, targetClass, foreignField, additionalForeignFields,
mergedPropertyType, componentProperties, idProperty, prefix, propertyName, type,
propertyForeignKey, additionalForeignKeyIndexPosition, presentationAttributes,
presentationAttribute, explicitType, returnedClass, this), fields);
}
}
protected boolean testForeignProperty(ForeignKey foreignField, String prefix, String propertyName) {
boolean isPropertyForeignKey = false;
if (foreignField != null) {
isPropertyForeignKey = foreignField.getManyToField().equals(prefix + propertyName);
}
return isPropertyForeignKey;
}
protected int findAdditionalForeignKeyIndex(ForeignKey[] additionalForeignFields, String prefix, String propertyName) {
int additionalForeignKeyIndexPosition = -1;
if (additionalForeignFields != null) {
additionalForeignKeyIndexPosition = Arrays.binarySearch(additionalForeignFields, new ForeignKey(prefix + propertyName, null, null), new Comparator<ForeignKey>() {
@Override
public int compare(ForeignKey o1, ForeignKey o2) {
return o1.getManyToField().compareTo(o2.getManyToField());
}
});
}
return additionalForeignKeyIndexPosition;
}
protected void buildEntityProperties(
Map<String, FieldMetadata> fields,
ForeignKey foreignField,
ForeignKey[] additionalForeignFields,
String[] additionalNonPersistentProperties,
Boolean populateManyToOneFields,
String[] includeFields,
String[] excludeFields,
String configurationKey,
String ceilingEntityFullyQualifiedClassname,
String propertyName,
Class<?> returnedClass,
Class<?> targetClass,
List<Class<?>> parentClasses,
String prefix,
Boolean isParentExcluded
) {
Class<?>[] polymorphicEntities = getAllPolymorphicEntitiesFromCeiling(returnedClass);
List<Class<?>> clonedParentClasses = new ArrayList<Class<?>>();
for (Class<?> parentClass : parentClasses) {
clonedParentClasses.add(parentClass);
}
clonedParentClasses.add(targetClass);
Map<String, FieldMetadata> newFields = getMergedPropertiesRecursively(
ceilingEntityFullyQualifiedClassname,
polymorphicEntities,
foreignField,
additionalNonPersistentProperties,
additionalForeignFields,
MergedPropertyType.PRIMARY,
populateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
clonedParentClasses,
prefix + propertyName + '.',
isParentExcluded
);
for (FieldMetadata newMetadata : newFields.values()) {
newMetadata.setInheritedFromType(targetClass.getName());
newMetadata.setAvailableToTypes(new String[]{targetClass.getName()});
}
Map<String, FieldMetadata> convertedFields = new HashMap<String, FieldMetadata>(newFields.size());
for (Map.Entry<String, FieldMetadata> key : newFields.entrySet()) {
convertedFields.put(propertyName + '.' + key.getKey(), key.getValue());
if (key.getValue() instanceof BasicFieldMetadata) {
for (Map.Entry<String, Map<String, String>> entry : ((BasicFieldMetadata) key.getValue()).getValidationConfigurations().entrySet()) {
Class<?> validatorImpl = null;
try {
validatorImpl = Class.forName(entry.getKey());
} catch (ClassNotFoundException e) {
Object bean = applicationContext.getBean(entry.getKey());
if (bean != null) {
validatorImpl = bean.getClass();
}
}
if (validatorImpl != null && FieldNamePropertyValidator.class.isAssignableFrom(validatorImpl)) {
for (Map.Entry<String, String> configs : entry.getValue().entrySet()) {
if (newFields.containsKey(configs.getValue())) {
configs.setValue(propertyName + "." + configs.getValue());
}
}
}
}
}
}
fields.putAll(convertedFields);
}
protected void buildComponentProperties(
Class<?> targetClass,
ForeignKey foreignField,
ForeignKey[] additionalForeignFields,
String[] additionalNonPersistentProperties,
MergedPropertyType mergedPropertyType,
Map<String, FieldMetadata> fields,
String idProperty,
Boolean populateManyToOneFields,
String[] includeFields,
String[] excludeFields,
String configurationKey,
String ceilingEntityFullyQualifiedClassname,
String propertyName,
Type type,
Class<?> returnedClass,
List<Class<?>> parentClasses,
Boolean isParentExcluded,
String prefix
) {
String[] componentProperties = ((ComponentType) type).getPropertyNames();
List<String> componentPropertyNames = Arrays.asList(componentProperties);
Type[] componentTypes = ((ComponentType) type).getSubtypes();
List<Type> componentPropertyTypes = Arrays.asList(componentTypes);
String tempPrefix = "";
int pos = prefix.indexOf(".");
if (pos > 0 && pos < prefix.length()-1) {
//only use part of the prefix if it's more than one layer deep
tempPrefix = prefix.substring(pos + 1, prefix.length());
}
Map<String, FieldMetadata> componentPresentationAttributes = metadata.getFieldPresentationAttributes(targetClass, returnedClass, this, tempPrefix + propertyName + ".");
if (isParentExcluded) {
for (String key : componentPresentationAttributes.keySet()) {
LOG.debug("buildComponentProperties:Excluding " + key + " because the parent was excluded");
componentPresentationAttributes.get(key).setExcluded(true);
}
}
PersistentClass persistentClass = getPersistentClass(targetClass.getName());
Property property;
try {
property = persistentClass.getProperty(propertyName);
} catch (MappingException e) {
property = persistentClass.getProperty(prefix + propertyName);
}
Iterator componentPropertyIterator = ((org.hibernate.mapping.Component) property.getValue()).getPropertyIterator();
List<Property> componentPropertyList = new ArrayList<Property>();
while(componentPropertyIterator.hasNext()) {
componentPropertyList.add((Property) componentPropertyIterator.next());
}
Map<String, FieldMetadata> newFields = new HashMap<String, FieldMetadata>();
buildProperties(
targetClass,
foreignField,
additionalForeignFields,
additionalNonPersistentProperties,
mergedPropertyType,
componentPresentationAttributes,
componentPropertyList,
newFields,
componentPropertyNames,
componentPropertyTypes,
idProperty,
populateManyToOneFields,
includeFields,
excludeFields,
configurationKey,
ceilingEntityFullyQualifiedClassname,
parentClasses,
propertyName + ".",
isParentExcluded,
true
);
Map<String, FieldMetadata> convertedFields = new HashMap<String, FieldMetadata>();
for (String key : newFields.keySet()) {
convertedFields.put(propertyName + "." + key, newFields.get(key));
}
fields.putAll(convertedFields);
}
@Override
public EntityManager getStandardEntityManager() {
return standardEntityManager;
}
@Override
public void setStandardEntityManager(EntityManager entityManager) {
this.standardEntityManager = entityManager;
}
@Override
public EJB3ConfigurationDao getEjb3ConfigurationDao() {
return ejb3ConfigurationDao;
}
public void setEjb3ConfigurationDao(EJB3ConfigurationDao ejb3ConfigurationDao) {
this.ejb3ConfigurationDao = ejb3ConfigurationDao;
}
@Override
public FieldManager getFieldManager() {
return new FieldManager(entityConfiguration, getStandardEntityManager());
}
@Override
public EntityConfiguration getEntityConfiguration() {
return entityConfiguration;
}
@Override
public void setEntityConfiguration(EntityConfiguration entityConfiguration) {
this.entityConfiguration = entityConfiguration;
}
@Override
public Metadata getMetadata() {
return metadata;
}
@Override
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
public List<FieldMetadataProvider> getFieldMetadataProviders() {
return fieldMetadataProviders;
}
public void setFieldMetadataProviders(List<FieldMetadataProvider> fieldMetadataProviders) {
this.fieldMetadataProviders = fieldMetadataProviders;
}
@Override
public FieldMetadataProvider getDefaultFieldMetadataProvider() {
return defaultFieldMetadataProvider;
}
public void setDefaultFieldMetadataProvider(FieldMetadataProvider defaultFieldMetadataProvider) {
this.defaultFieldMetadataProvider = defaultFieldMetadataProvider;
}
protected boolean isExcludeClassFromPolymorphism(Class<?> clazz) {
return dynamicDaoHelper.isExcludeClassFromPolymorphism(clazz);
}
@Override
public DynamicDaoHelper getDynamicDaoHelper() {
return dynamicDaoHelper;
}
public void setDynamicDaoHelper(DynamicDaoHelper dynamicDaoHelper) {
this.dynamicDaoHelper = dynamicDaoHelper;
}
}