/*
* Copyright 2004-2005 the original author or authors.
*
* 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.
*/
package org.grails.core;
import grails.core.ComponentCapableDomainClass;
import grails.core.GrailsDomainClass;
import grails.core.GrailsDomainClassProperty;
import grails.util.GrailsClassUtils;
import grails.util.GrailsNameUtils;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.grails.core.artefact.DomainClassArtefactHandler;
import org.grails.core.io.support.GrailsFactoriesLoader;
import org.grails.core.exceptions.GrailsDomainException;
import org.grails.core.exceptions.InvalidPropertyException;
import grails.validation.ConstraintsEvaluator;
import org.grails.core.support.GrailsDomainConfigurationUtil;
import org.grails.core.util.ClassPropertyFetcher;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.Validator;
/**
* @author Graeme Rocher
*/
@SuppressWarnings("rawtypes")
public class DefaultGrailsDomainClass extends AbstractGrailsClass implements GrailsDomainClass, ComponentCapableDomainClass{
private GrailsDomainClassProperty identifier;
private GrailsDomainClassProperty version;
private GrailsDomainClassProperty[] properties;
private GrailsDomainClassProperty[] persistentProperties;
private Map<String, GrailsDomainClassProperty> propertyMap;
private Map relationshipMap;
private Map hasOneMap;
private Map constraints;
private Map mappedBy;
private Validator validator;
private String mappingStrategy = GrailsDomainClass.GORM;
private List<Class<?>> owners = new ArrayList<Class<?>>();
private boolean root = true;
private Set subClasses = new HashSet();
private Collection<String> embedded;
private Map<String, Object> defaultConstraints;
private List<GrailsDomainClass> components = new ArrayList<GrailsDomainClass>();
private List<GrailsDomainClassProperty> associations = new ArrayList<GrailsDomainClassProperty>();
/**
* Constructor.
* @param clazz
* @param defaultConstraints
*/
public DefaultGrailsDomainClass(Class<?> clazz, Map<String, Object> defaultConstraints) {
super(clazz, "");
PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors();
final Class<?> superClass = clazz.getSuperclass();
if (DomainClassArtefactHandler.isDomainClass(superClass)) {
root = false;
}
propertyMap = new LinkedHashMap<String, GrailsDomainClassProperty>();
relationshipMap = getAssociationMap();
embedded = getEmbeddedList();
this.defaultConstraints = defaultConstraints;
// get mapping strategy by setting
mappingStrategy = getStaticPropertyValue(GrailsDomainClassProperty.MAPPING_STRATEGY, String.class);
if (mappingStrategy == null) {
mappingStrategy = GORM;
}
// get any mappedBy settings
mappedBy = getMergedConfigurationMap(GrailsDomainClassProperty.MAPPED_BY);
hasOneMap = getMergedConfigurationMap(GrailsDomainClassProperty.HAS_ONE);
if (hasOneMap == null) {
hasOneMap = Collections.emptyMap();
}
if (mappedBy == null) {
mappedBy = Collections.emptyMap();
}
// establish the owners of relationships
establishRelationshipOwners();
// First go through the properties of the class and create domain properties
// populating into a map
populateDomainClassProperties(propertyDescriptors);
// if no identifier property throw exception
if (identifier == null) {
throw new GrailsDomainException("Identity property not found, but required in domain class ["+getFullName()+"]");
}
// if no version property throw exception
if (version == null) {
throw new GrailsDomainException("Version property not found, but required in domain class ["+getFullName()+"]");
}
// set properties from map values
properties = propertyMap.values().toArray(new GrailsDomainClassProperty[propertyMap.size()]);
// establish relationships
establishRelationships();
// set persistent properties
establishPersistentProperties();
}
/**
* Constructor.
* @param clazz
*/
public DefaultGrailsDomainClass(Class<?> clazz) {
this(clazz, null);
}
public boolean hasSubClasses() {
return !getSubClasses().isEmpty();
}
/**
* calculates the persistent properties from the evaluated properties
*/
private void establishPersistentProperties() {
Collection<GrailsDomainClassProperty> tempList = new ArrayList<GrailsDomainClassProperty>();
for (Object o : propertyMap.values()) {
GrailsDomainClassProperty currentProp = (GrailsDomainClassProperty) o;
if (currentProp.getType() != Object.class && currentProp.isPersistent() &&
!currentProp.isIdentity() && !currentProp.getName().equals(GrailsDomainClassProperty.VERSION)) {
tempList.add(currentProp);
}
}
persistentProperties = tempList.toArray(new GrailsDomainClassProperty[tempList.size()]);
}
/**
* Evaluates the belongsTo property to find out who owns who
*/
@SuppressWarnings("unchecked")
private void establishRelationshipOwners() {
Class<?> belongsTo = getStaticPropertyValue(GrailsDomainClassProperty.BELONGS_TO, Class.class);
if (belongsTo == null) {
List ownersProp = getStaticPropertyValue(GrailsDomainClassProperty.BELONGS_TO, List.class);
if (ownersProp != null) {
owners = ownersProp;
}
else {
Map ownersMap = getStaticPropertyValue(GrailsDomainClassProperty.BELONGS_TO, Map.class);
if (ownersMap!=null) {
owners = new ArrayList(ownersMap.values());
}
}
}
else {
owners = new ArrayList();
owners.add(belongsTo);
}
}
/**
* Populates the domain class properties map
*
* @param propertyDescriptors The property descriptors
*/
private void populateDomainClassProperties(PropertyDescriptor[] propertyDescriptors) {
for (PropertyDescriptor descriptor : propertyDescriptors) {
if (descriptor.getPropertyType() == null) {
// indexed property
continue;
}
// ignore certain properties
if (GrailsDomainConfigurationUtil.isNotConfigurational(descriptor)) {
GrailsDomainClassProperty property = new DefaultGrailsDomainClassProperty(this, descriptor, defaultConstraints);
propertyMap.put(property.getName(), property);
if (property.isIdentity()) {
identifier = property;
}
else if (property.getName().equals(GrailsDomainClassProperty.VERSION)) {
version = property;
}
}
}
}
/**
* Retrieves the association map
*/
public Map getAssociationMap() {
if (relationshipMap == null) {
relationshipMap = getMergedConfigurationMap(GrailsDomainClassProperty.HAS_MANY);
}
return relationshipMap;
}
@SuppressWarnings("unchecked")
private Map getMergedConfigurationMap(String propertyName) {
Map configurationMap = getStaticPropertyValue(propertyName, Map.class);
if (configurationMap == null) {
configurationMap = new HashMap();
}
Class<?> theClass = getClazz();
while (theClass != Object.class) {
theClass = theClass.getSuperclass();
ClassPropertyFetcher propertyFetcher = ClassPropertyFetcher.forClass(theClass);
Map superRelationshipMap = propertyFetcher.getStaticPropertyValue(propertyName, Map.class);
if (superRelationshipMap != null && !superRelationshipMap.equals(configurationMap)) {
configurationMap.putAll(superRelationshipMap);
}
}
return configurationMap;
}
/**
* Retrieves the list of known embedded component types
*
* @return A list of embedded components
*/
@SuppressWarnings("unchecked")
private Collection<String> getEmbeddedList() {
Collection potentialList = getStaticPropertyValue(GrailsDomainClassProperty.EMBEDDED, Collection.class);
if (potentialList != null) {
return potentialList;
}
return Collections.emptyList();
}
/**
* Calculates the relationship type based other types referenced
*/
private void establishRelationships() {
for (Object o : propertyMap.values()) {
DefaultGrailsDomainClassProperty currentProp = (DefaultGrailsDomainClassProperty) o;
if (!currentProp.isPersistent()) continue;
Class currentPropType = currentProp.getType();
// establish if the property is a one-to-many
// if it is a Set/Collection and there are relationships defined
// and it is defined as persistent
if (currentPropType != null) {
if (Collection.class.isAssignableFrom(currentPropType) || Map.class.isAssignableFrom(currentPropType)) {
establishRelationshipForCollection(currentProp);
}
// otherwise if the type is a domain class establish relationship
else if (DomainClassArtefactHandler.isDomainClass(currentPropType) &&
currentProp.isPersistent()) {
associations.add(currentProp);
establishDomainClassRelationship(currentProp);
}
else if (embedded.contains(currentProp.getName())) {
associations.add(currentProp);
establishDomainClassRelationship(currentProp);
}
}
}
}
/**
* Establishes a relationship for a java.util.Set
*
* @param property The collection property
*/
private void establishRelationshipForCollection(DefaultGrailsDomainClassProperty property) {
// is it a relationship
Class<?> relatedClassType = getRelatedClassType(property.getName());
if (relatedClassType != null) {
// set the referenced type in the property
associations.add(property);
property.setReferencedPropertyType(relatedClassType);
// if the related type is a domain class
// then figure out what kind of relationship it is
if (DomainClassArtefactHandler.isDomainClass(relatedClassType)) {
// check the relationship defined in the referenced type
// if it is also a Set/domain class etc.
Map relatedClassRelationships = GrailsDomainConfigurationUtil.getAssociationMap(relatedClassType);
Class<?> relatedClassPropertyType = null;
// First check whether there is an explicit relationship
// mapping for this property (as provided by "mappedBy").
String mappingProperty = (String)mappedBy.get(property.getName());
if (StringUtils.hasText(mappingProperty)) {
// First find the specified property on the related class, if it exists.
PropertyDescriptor pd = findProperty(GrailsClassUtils.getPropertiesOfType(relatedClassType, getClazz()), mappingProperty);
// If a property of the required type does not exist, search
// for any collection properties on the related class.
if (pd == null) pd = findProperty(GrailsClassUtils.getPropertiesAssignableToType(relatedClassType, Collection.class), mappingProperty);
// We've run out of options. The given "mappedBy"
// setting is invalid.
boolean isNone = "none".equals(mappingProperty);
if (pd == null && !isNone) {
throw new GrailsDomainException("Non-existent mapping property ["+mappingProperty+"] specified for property ["+property.getName()+"] in class ["+getClazz()+"]");
}
else if (pd != null) {
// Tie the properties together.
relatedClassPropertyType = pd.getPropertyType();
property.setReferencePropertyName(pd.getName());
}
}
else {
if(mappedBy.containsKey(property.getName()) && mappedBy.get(property.getName()) == null) return;
// if the related type has a relationships map it may be a many-to-many
// figure out if there is a many-to-many relationship defined
if (isRelationshipManyToMany(property, relatedClassType, relatedClassRelationships)) {
String relatedClassPropertyName = null;
Map relatedClassMappedBy = GrailsDomainConfigurationUtil.getMappedByMap(relatedClassType);
// retrieve the relationship property
for (Object o : relatedClassRelationships.keySet()) {
String currentKey = (String) o;
String mappedByProperty = (String) relatedClassMappedBy.get(currentKey);
if (mappedByProperty != null && !mappedByProperty.equals(property.getName())) continue;
Class<?> currentClass = (Class<?>)relatedClassRelationships.get(currentKey);
if (currentClass.isAssignableFrom(getClazz())) {
relatedClassPropertyName = currentKey;
break;
}
}
// if there is one defined get the type
if (relatedClassPropertyName != null) {
relatedClassPropertyType = GrailsClassUtils.getPropertyType(relatedClassType, relatedClassPropertyName);
}
}
// otherwise figure out if there is a one-to-many relationship by retrieving any properties that are of the related type
// if there is more than one property then (for the moment) ignore the relationship
if (relatedClassPropertyType == null) {
PropertyDescriptor[] descriptors = GrailsClassUtils.getPropertiesOfType(relatedClassType, getClazz());
if (descriptors.length == 1) {
relatedClassPropertyType = descriptors[0].getPropertyType();
property.setReferencePropertyName(descriptors[0].getName());
}
else if (descriptors.length > 1) {
// try now to use the class name by convention
String classPropertyName = getPropertyName();
PropertyDescriptor pd = findProperty(descriptors, classPropertyName);
if (pd == null) {
throw new GrailsDomainException("Property ["+property.getName()+"] in class ["+getClazz()+"] is a bidirectional one-to-many with two possible properties on the inverse side. "+
"Either name one of the properties on other side of the relationship ["+classPropertyName+"] or use the 'mappedBy' static to define the property " +
"that the relationship is mapped with. Example: static mappedBy = ["+property.getName()+":'myprop']");
}
relatedClassPropertyType = pd.getPropertyType();
property.setReferencePropertyName(pd.getName());
}
}
}
establishRelationshipForSetToType(property,relatedClassPropertyType);
// if its a many-to-many figure out the owning side of the relationship
if (property.isManyToMany()) {
establishOwnerOfManyToMany(property, relatedClassType);
}
}
// otherwise set it to not persistent as you can't persist
// relationships to non-domain classes
else {
property.setBasicCollectionType(true);
}
}
else if (!Collection.class.isAssignableFrom(property.getType()) && !Map.class.isAssignableFrom(property.getType())) {
// no relationship defined for set/collection.
// set/collection not persistent
property.setPersistent(false);
}
}
/**
* Finds a property type is an array of descriptors for the given property name
*
* @param descriptors The descriptors
* @param propertyName The property name
* @return The Class or null
*/
private PropertyDescriptor findProperty(PropertyDescriptor[] descriptors, String propertyName) {
PropertyDescriptor d = null;
for (PropertyDescriptor descriptor : descriptors) {
if (descriptor.getName().equals(propertyName)) {
d = descriptor;
break;
}
}
return d;
}
/**
* Find out if the relationship is a many-to-many
*
* @param property The property
* @param relatedClassType The related type
* @param relatedClassRelationships The related types relationships
* @return <code>true</code> if the relationship is a many-to-many
*/
private boolean isRelationshipManyToMany(DefaultGrailsDomainClassProperty property,
Class<?> relatedClassType, Map relatedClassRelationships) {
return relatedClassRelationships != null &&
!relatedClassRelationships.isEmpty() &&
!relatedClassType.equals(property.getDomainClass().getClazz());
}
/**
* Inspects a related classes' ownership settings against this properties class' ownership
* settings to find out who owns a many-to-many relationship
*
* @param property The property
* @param relatedClassType The related type
*/
@SuppressWarnings("unchecked")
private void establishOwnerOfManyToMany(DefaultGrailsDomainClassProperty property, Class<?> relatedClassType) {
ClassPropertyFetcher cpf = ClassPropertyFetcher.forClass(relatedClassType);
Object relatedBelongsTo = cpf.getPropertyValue(GrailsDomainClassProperty.BELONGS_TO);
boolean owningSide = false;
boolean relatedOwner = isOwningSide(relatedClassType, owners);
final Class<?> propertyClass = property.getDomainClass().getClazz();
if (relatedBelongsTo instanceof Collection) {
final Collection associatedOwners = (Collection)relatedBelongsTo;
owningSide = isOwningSide(propertyClass, associatedOwners);
}
else if (relatedBelongsTo instanceof Class) {
final Collection associatedOwners = new ArrayList();
associatedOwners.add(relatedBelongsTo);
owningSide = isOwningSide(propertyClass, associatedOwners);
}
property.setOwningSide(owningSide);
if (relatedOwner && property.isOwningSide()) {
throw new GrailsDomainException("Domain classes [" + propertyClass +
"] and [" + relatedClassType +
"] cannot own each other in a many-to-many relationship. Both contain belongsTo definitions that reference each other.");
}
if (!relatedOwner && !property.isOwningSide() && !(property.isCircular() && property.isManyToMany())) {
throw new GrailsDomainException("No owner defined between domain classes ["+propertyClass+"] and ["+relatedClassType+"] in a many-to-many relationship. Example: static belongsTo = "+relatedClassType.getName());
}
}
private boolean isOwningSide(Class<?> relatedClassType, Collection<Class<?>> potentialOwners) {
boolean relatedOwner = false;
for (Class<?> relatedClass : potentialOwners) {
if (relatedClass.isAssignableFrom(relatedClassType)) {
relatedOwner = true;
break;
}
}
return relatedOwner;
}
/**
* Establishes whether the relationship is a bi-directional or uni-directional one-to-many
* and applies the appropriate settings to the specified property
*
* @param property The property to apply settings to
* @param relatedClassPropertyType The related type
*/
private void establishRelationshipForSetToType(DefaultGrailsDomainClassProperty property,
Class<?> relatedClassPropertyType) {
if (relatedClassPropertyType == null) {
// uni-directional one-to-many
property.setOneToMany(true);
property.setBidirectional(false);
}
else if (Collection.class.isAssignableFrom(relatedClassPropertyType) ||
Map.class.isAssignableFrom(relatedClassPropertyType)) {
// many-to-many
property.setManyToMany(true);
property.setBidirectional(true);
}
else if (DomainClassArtefactHandler.isDomainClass(relatedClassPropertyType)) {
// bi-directional one-to-many
property.setOneToMany(true);
property.setBidirectional(true);
}
}
/**
* Establish relationship with related domain class
*
* @param property Establishes a relationship between this class and the domain class property
*/
private void establishDomainClassRelationship(DefaultGrailsDomainClassProperty property) {
Class<?> propType = property.getType();
if (embedded.contains(property.getName())) {
property.setEmbedded(true);
return;
}
// establish relationship to type
Map relatedClassRelationships = GrailsDomainConfigurationUtil.getAssociationMap(propType);
Map mappedBy = GrailsDomainConfigurationUtil.getMappedByMap(propType);
Class<?> relatedClassPropertyType = null;
if(mappedBy.containsKey(property.getName()) && mappedBy.get(property.getName()) == null) return;
// if there is a relationships map use that to find out
// whether it is mapped to a Set
if (relatedClassRelationships != null && !relatedClassRelationships.isEmpty()) {
String relatedClassPropertyName = findOneToManyThatMatchesType(property, relatedClassRelationships);
PropertyDescriptor[] descriptors = GrailsClassUtils.getPropertiesOfType(getClazz(), property.getType());
// if there is only one property on many-to-one side of the relationship then
// try to establish if it is bidirectional
if (descriptors.length == 1 && isNotMappedToDifferentProperty(property,relatedClassPropertyName, mappedBy)) {
if (StringUtils.hasText(relatedClassPropertyName)) {
property.setReferencePropertyName(relatedClassPropertyName);
// get the type of the property
relatedClassPropertyType = GrailsClassUtils.getPropertyType(propType, relatedClassPropertyName);
}
}
// if there is more than one property on the many-to-one side then we need to either
// find out if there is a mappedBy property or whether a convention is used to decide
// on the mapping property
else if (descriptors.length > 1) {
if (mappedBy.containsValue(property.getName())) {
for (Object o : mappedBy.keySet()) {
String mappedByPropertyName = (String) o;
if (property.getName().equals(mappedBy.get(mappedByPropertyName))) {
Class<?> mappedByRelatedType = (Class<?>) relatedClassRelationships.get(mappedByPropertyName);
if (mappedByRelatedType != null && propType.isAssignableFrom(mappedByRelatedType))
relatedClassPropertyType = GrailsClassUtils.getPropertyType(propType, mappedByPropertyName);
}
}
}
else {
String classNameAsProperty = GrailsNameUtils.getPropertyName(propType);
if (property.getName().equals(classNameAsProperty) && !mappedBy.containsKey(relatedClassPropertyName)) {
relatedClassPropertyType = GrailsClassUtils.getPropertyType(propType, relatedClassPropertyName);
}
}
}
}
// otherwise retrieve all the properties of the type from the associated class
if (relatedClassPropertyType == null) {
PropertyDescriptor[] descriptors = GrailsClassUtils.getPropertiesOfType(propType, getClazz());
// if there is only one then the association is established
if (descriptors.length == 1) {
relatedClassPropertyType = descriptors[0].getPropertyType();
}
}
// establish relationship based on this type
establishDomainClassRelationshipToType(property, relatedClassPropertyType);
}
private boolean isNotMappedToDifferentProperty(GrailsDomainClassProperty property,
String relatedClassPropertyName, Map mappedBy) {
String mappedByForRelation = (String)mappedBy.get(relatedClassPropertyName);
if (mappedByForRelation == null) return true;
if (!property.getName().equals(mappedByForRelation)) return false;
return true;
}
private String findOneToManyThatMatchesType(DefaultGrailsDomainClassProperty property, Map relatedClassRelationships) {
String relatedClassPropertyName = null;
for (Object o : relatedClassRelationships.keySet()) {
String currentKey = (String) o;
Class<?> currentClass = (Class<?>)relatedClassRelationships.get(currentKey);
if (property.getDomainClass().getClazz().getName().equals(currentClass.getName())) {
relatedClassPropertyName = currentKey;
break;
}
}
return relatedClassPropertyName;
}
private void establishDomainClassRelationshipToType(DefaultGrailsDomainClassProperty property, Class<?> relatedClassPropertyType) {
// uni-directional one-to-one
if (relatedClassPropertyType == null) {
if (hasOneMap.containsKey(property.getName())) {
property.setHasOne(true);
}
property.setOneToOne(true);
property.setBidirectional(false);
}
// bi-directional many-to-one
else if (Collection.class.isAssignableFrom(relatedClassPropertyType)||Map.class.isAssignableFrom(relatedClassPropertyType)) {
property.setManyToOne(true);
property.setBidirectional(true);
}
// bi-directional one-to-one
else if (DomainClassArtefactHandler.isDomainClass(relatedClassPropertyType)) {
if (hasOneMap.containsKey(property.getName())) {
property.setHasOne(true);
}
property.setOneToOne(true);
if (!getClazz().equals(relatedClassPropertyType)) {
property.setBidirectional(true);
}
}
}
public boolean isOwningClass(Class domainClass) {
return owners.contains(domainClass);
}
/* (non-Javadoc)
* @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getProperties()
*/
public GrailsDomainClassProperty[] getProperties() {
return properties;
}
/* (non-Javadoc)
* @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getIdentifier()
*/
public GrailsDomainClassProperty getIdentifier() {
return identifier;
}
/* (non-Javadoc)
* @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getVersion()
*/
public GrailsDomainClassProperty getVersion() {
return version;
}
/**
* @see grails.core.GrailsDomainClass#getPersistantProperties()
*/
@Deprecated
public GrailsDomainClassProperty[] getPersistantProperties() {
return persistentProperties;
}
public GrailsDomainClassProperty[] getPersistentProperties() {
return persistentProperties;
}
/* (non-Javadoc)
* @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getPropertyByName(java.lang.String)
*/
public GrailsDomainClassProperty getPropertyByName(String name) {
GrailsDomainClassProperty persistentProperty = getPersistentProperty(name);
if (persistentProperty == null) {
throw new InvalidPropertyException("No property found for name ["+name+"] for class ["+getClazz()+"]");
}
return persistentProperty;
}
public GrailsDomainClassProperty getPersistentProperty(String name) {
if (propertyMap.containsKey(name)) {
return propertyMap.get(name);
}
int indexOfDot = name.indexOf('.');
if (indexOfDot > 0) {
String basePropertyName = name.substring(0, indexOfDot);
if (propertyMap.containsKey(basePropertyName)) {
GrailsDomainClassProperty prop = propertyMap.get(basePropertyName);
GrailsDomainClass referencedDomainClass = prop.getReferencedDomainClass();
if (referencedDomainClass != null) {
String restOfPropertyName = name.substring(indexOfDot + 1);
return referencedDomainClass.getPropertyByName(restOfPropertyName);
}
}
}
return null;
}
/* (non-Javadoc)
* @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getFieldName(java.lang.String)
*/
public String getFieldName(String propertyName) {
return getPropertyByName(propertyName).getFieldName();
}
/* (non-Javadoc)
* @see org.grails.core.AbstractGrailsClass#getName()
*/
@Override
public String getName() {
return ClassUtils.getShortName(super.getName());
}
/* (non-Javadoc)
* @see org.codehaus.groovy.grails.domain.GrailsDomainClass#isOneToMany(java.lang.String)
*/
public boolean isOneToMany(String propertyName) {
return getPropertyByName(propertyName).isOneToMany();
}
/* (non-Javadoc)
* @see org.codehaus.groovy.grails.domain.GrailsDomainClass#isManyToOne(java.lang.String)
*/
public boolean isManyToOne(String propertyName) {
return getPropertyByName(propertyName).isManyToOne();
}
/* (non-Javadoc)
* @see grails.core.GrailsDomainClass#getRelationshipType(java.lang.String)
*/
public Class<?> getRelatedClassType(String propertyName) {
return (Class<?>)relationshipMap.get(propertyName);
}
/* (non-Javadoc)
* @see grails.core.GrailsDomainClass#getPropertyName()
*/
@Override
public String getPropertyName() {
return GrailsNameUtils.getPropertyNameRepresentation(getClazz());
}
/* (non-Javadoc)
* @see grails.core.GrailsDomainClass#isBidirectional()
*/
public boolean isBidirectional(String propertyName) {
return getPropertyByName(propertyName).isBidirectional();
}
/* (non-Javadoc)
* @see grails.core.GrailsDomainClass#getConstraints()
*/
@SuppressWarnings("unchecked")
public Map getConstrainedProperties() {
if (constraints == null) {
initializeConstraints();
}
return Collections.unmodifiableMap(constraints);
}
private void initializeConstraints() {
// process the constraints
final ConstraintsEvaluator constraintsEvaluator = getConstraintsEvaluator();
if(constraintsEvaluator != null) {
constraints = constraintsEvaluator.evaluate(getClazz(), persistentProperties);
}
else {
constraints = Collections.emptyMap();
}
}
/* (non-Javadoc)
* @see grails.core.GrailsDomainClass#getValidator()
*/
public Validator getValidator() {
return validator;
}
/* (non-Javadoc)
* @see grails.core.GrailsDomainClass#setValidator(Validator validator)
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/* (non-Javadoc)
* @see grails.core.GrailsDomainClass#getMappedBy()
*/
public String getMappingStrategy() {
return mappingStrategy;
}
public boolean isRoot() {
return root;
}
@SuppressWarnings("unchecked")
public Set getSubClasses() {
return subClasses;
}
public void refreshConstraints() {
final ConstraintsEvaluator constraintEvaluator = getConstraintsEvaluator();
if (defaultConstraints!=null) {
constraints = constraintEvaluator.evaluate(getClazz(), persistentProperties);
}
else {
constraints = constraintEvaluator.evaluate(getClazz(), persistentProperties);
}
// Embedded components have their own ComponentDomainClass instance which
// won't be refreshed by the application. So, we have to do it here.
for (GrailsDomainClassProperty property : persistentProperties) {
if (property.isEmbedded()) {
property.getComponent().refreshConstraints();
}
}
}
ConstraintsEvaluator getConstraintsEvaluator() {
if (grailsApplication != null && grailsApplication.getMainContext() != null) {
final ApplicationContext context = grailsApplication.getMainContext();
if (context.containsBean(ConstraintsEvaluator.BEAN_NAME)) {
return context.getBean(ConstraintsEvaluator.BEAN_NAME, ConstraintsEvaluator.class);
}
}
return GrailsFactoriesLoader.loadFactory(ConstraintsEvaluator.class, defaultConstraints);
}
public Map getMappedBy() {
return mappedBy;
}
public boolean hasPersistentProperty(String propertyName) {
for (GrailsDomainClassProperty persistentProperty : persistentProperties) {
if (persistentProperty.getName().equals(propertyName)) return true;
}
return false;
}
public void setMappingStrategy(String strategy) {
mappingStrategy = strategy;
}
public void addComponent(GrailsDomainClass component) {
components.add(component);
}
public List<GrailsDomainClass> getComponents() {
return Collections.unmodifiableList(components);
}
public List<GrailsDomainClassProperty> getAssociations() {
return associations;
}
}