GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / commons / org / codehaus / groovy / grails / commons / DefaultGrailsDomainClass.java
blob48b84975f3df20823d099e94f5289ffac52d3d30
1 /* Copyright 2004-2005 the original author or authors.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
15 package org.codehaus.groovy.grails.commons;
18 import groovy.lang.GroovyObject;
19 import org.apache.commons.lang.ClassUtils;
20 import org.apache.commons.lang.StringUtils;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.codehaus.groovy.grails.exceptions.GrailsDomainException;
24 import org.codehaus.groovy.grails.exceptions.InvalidPropertyException;
25 import org.springframework.beans.BeanUtils;
26 import org.springframework.validation.Validator;
28 import java.beans.PropertyDescriptor;
29 import java.beans.IntrospectionException;
30 import java.lang.reflect.Modifier;
31 import java.util.*;
33 /**
34 * @author Graeme Rocher
35 * @since 05-Jul-2005
37 public class DefaultGrailsDomainClass extends AbstractGrailsClass implements GrailsDomainClass {
39 private static final Log LOG = LogFactory.getLog(DefaultGrailsDomainClass.class);
42 private GrailsDomainClassProperty identifier;
43 private GrailsDomainClassProperty version;
44 private GrailsDomainClassProperty[] properties;
45 private GrailsDomainClassProperty[] persistantProperties;
46 private Map propertyMap;
47 private Map relationshipMap;
49 private Map constraints = new HashMap();
50 private Map mappedBy;
51 private Validator validator;
52 private String mappingStrategy = GrailsDomainClass.GORM;
53 private List owners = new ArrayList();
54 private boolean root = true;
55 private Set subClasses = new HashSet();
56 private Collection embedded;
58 public DefaultGrailsDomainClass(Class clazz) {
59 super(clazz, "");
60 PropertyDescriptor[] propertyDescriptors = getReference().getPropertyDescriptors();
62 if(!clazz.getSuperclass().equals( GroovyObject.class ) &&
63 !clazz.getSuperclass().equals(Object.class) &&
64 !Modifier.isAbstract(clazz.getSuperclass().getModifiers())) {
65 this.root = false;
67 this.propertyMap = new LinkedHashMap();
68 this.relationshipMap = getAssociationMap();
69 this.embedded = getEmbeddedList();
71 // get mapping strategy by setting
72 if(getPropertyOrStaticPropertyOrFieldValue(GrailsDomainClassProperty.MAPPING_STRATEGY, String.class) != null)
73 this.mappingStrategy = (String)getPropertyOrStaticPropertyOrFieldValue(GrailsDomainClassProperty.MAPPING_STRATEGY, String.class);
75 // get any mappedBy settings
76 this.mappedBy = (Map)getPropertyOrStaticPropertyOrFieldValue(GrailsDomainClassProperty.MAPPED_BY, Map.class);
77 if(this.mappedBy == null)this.mappedBy = Collections.EMPTY_MAP;
79 // establish the owners of relationships
80 establishRelationshipOwners();
82 // First go through the properties of the class and create domain properties
83 // populating into a map
84 populateDomainClassProperties(propertyDescriptors);
86 // if no identifier property throw exception
87 if(this.identifier == null) {
88 throw new GrailsDomainException("Identity property not found, but required in domain class ["+getFullName()+"]" );
90 // if no version property throw exception
91 if(this.version == null) {
92 throw new GrailsDomainException("Version property not found, but required in domain class ["+getFullName()+"]" );
94 // set properties from map values
95 this.properties = (GrailsDomainClassProperty[])this.propertyMap.values().toArray( new GrailsDomainClassProperty[this.propertyMap.size()] );
97 // establish relationships
98 establishRelationships();
100 // set persistant properties
101 establishPersistentProperties();
102 // process the constraints
103 try {
104 this.constraints = GrailsDomainConfigurationUtil.evaluateConstraints(getReference().getWrappedInstance(), this.persistantProperties);
105 } catch (IntrospectionException e) {
106 LOG.error("Error reading class ["+getClazz()+"] constraints: " +e .getMessage(), e);
113 public boolean hasSubClasses() {
114 return getSubClasses().size() > 0;
120 * calculates the persistent properties from the evaluated properties
122 private void establishPersistentProperties() {
123 Collection tempList = new ArrayList();
124 for(Iterator i = this.propertyMap.values().iterator();i.hasNext();) {
125 GrailsDomainClassProperty currentProp = (GrailsDomainClassProperty)i.next();
126 if(currentProp.getType() != Object.class && currentProp.isPersistent() && !currentProp.isIdentity() && !currentProp.getName().equals( GrailsDomainClassProperty.VERSION )) {
127 tempList.add(currentProp);
130 this.persistantProperties = (GrailsDomainClassProperty[])tempList.toArray( new GrailsDomainClassProperty[tempList.size()]);
134 * Evaluates the belongsTo property to find out who owns who
136 private void establishRelationshipOwners() {
137 Class belongsTo = (Class)getPropertyOrStaticPropertyOrFieldValue(GrailsDomainClassProperty.BELONGS_TO, Class.class);
138 if(belongsTo == null) {
139 List ownersProp = (List)getPropertyOrStaticPropertyOrFieldValue(GrailsDomainClassProperty.BELONGS_TO, List.class);
140 if(ownersProp != null) {
141 this.owners = ownersProp;
143 else {
144 Map ownersMap = (Map)getPropertyOrStaticPropertyOrFieldValue(GrailsDomainClassProperty.BELONGS_TO, Map.class);
145 if(ownersMap!=null) {
146 this.owners = new ArrayList(ownersMap.values());
150 else {
151 this.owners = new ArrayList();
152 this.owners.add(belongsTo);
157 * Populates the domain class properties map
159 * @param propertyDescriptors The property descriptors
161 private void populateDomainClassProperties(PropertyDescriptor[] propertyDescriptors) {
162 for(int i = 0; i < propertyDescriptors.length; i++) {
164 PropertyDescriptor descriptor = propertyDescriptors[i];
165 // ignore certain properties
166 if(GrailsDomainConfigurationUtil.isNotConfigurational(descriptor) ) {
169 GrailsDomainClassProperty property = new DefaultGrailsDomainClassProperty(this, descriptor);
170 this.propertyMap.put(property.getName(), property);
172 if(property.isIdentity()) {
173 this.identifier = property;
175 else if(property.getName().equals( GrailsDomainClassProperty.VERSION )) {
176 this.version = property;
184 * Retrieves the association map
186 public Map getAssociationMap() {
187 if(this.relationshipMap == null) {
188 relationshipMap = (Map)getPropertyOrStaticPropertyOrFieldValue( GrailsDomainClassProperty.HAS_MANY, Map.class );
189 if(relationshipMap == null)
190 this.relationshipMap = new HashMap();
192 Class theClass = getClazz();
193 while(theClass != Object.class) {
194 theClass = theClass.getSuperclass();
195 Map superRelationshipMap = (Map)GrailsClassUtils.getStaticPropertyValue(theClass, GrailsDomainClassProperty.HAS_MANY);
196 if(superRelationshipMap != null && !superRelationshipMap.equals(relationshipMap)) {
197 relationshipMap.putAll(superRelationshipMap);
201 return this.relationshipMap;
205 * Retrieves the list of known embedded component types
207 * @return A list of embedded components
209 private Collection getEmbeddedList() {
210 Object potentialList = GrailsClassUtils.getStaticPropertyValue(getClazz(), GrailsDomainClassProperty.EMBEDDED);
211 if(potentialList instanceof Collection) {
212 return (Collection)potentialList;
214 return Collections.EMPTY_LIST;
219 * Calculates the relationship type based other types referenced
222 private void establishRelationships() {
223 for(Iterator i = this.propertyMap.values().iterator();i.hasNext(); ) {
224 DefaultGrailsDomainClassProperty currentProp = (DefaultGrailsDomainClassProperty)i.next();
225 Class currentPropType = currentProp.getType();
226 // establish if the property is a one-to-many
227 // if it is a Set and there are relationships defined
228 // and it is defined as persistent
229 if( Collection.class.isAssignableFrom(currentPropType) || Map.class.isAssignableFrom(currentPropType) &&
230 currentProp.isPersistent() ) {
232 establishRelationshipForCollection( currentProp);
234 // otherwise if the type is a domain class establish relationship
235 else if(DomainClassArtefactHandler.isDomainClass(currentPropType) &&
236 currentProp.isPersistent()) {
238 establishDomainClassRelationship( currentProp );
240 else if(!GrailsDomainConfigurationUtil.isBasicType(currentProp)) {
241 establishDomainClassRelationship( currentProp );
249 * Establishes a relationship for a java.util.Set
251 * @param property The collection property
253 private void establishRelationshipForCollection(DefaultGrailsDomainClassProperty property) {
254 // is it a relationship
255 Class relatedClassType = getRelatedClassType( property.getName() );
258 if(relatedClassType != null) {
259 // set the referenced type in the property
260 property.setReferencedPropertyType(relatedClassType);
262 // if the related type is a domain class
263 // then figure out what kind of relationship it is
264 if(DomainClassArtefactHandler.isDomainClass(relatedClassType)) {
267 // check the relationship defined in the referenced type
268 // if it is also a Set/domain class etc.
269 Map relatedClassRelationships = GrailsDomainConfigurationUtil.getAssociationMap(relatedClassType);
270 Class relatedClassPropertyType = null;
272 // First check whether there is an explicit relationship
273 // mapping for this property (as provided by "mappedBy").
274 String mappingProperty = (String)this.mappedBy.get(property.getName());
275 if(!StringUtils.isBlank(mappingProperty)) {
276 // First find the specified property on the related
277 // class, if it exists.
278 PropertyDescriptor pd = findProperty(GrailsClassUtils.getPropertiesOfType(relatedClassType, getClazz()), mappingProperty);
280 // If a property of the required type does not exist,
281 // search for any collection properties on the related
282 // class.
283 if(pd == null) pd = findProperty(GrailsClassUtils.getPropertiesAssignableToType(relatedClassType, Collection.class), mappingProperty);
285 // We've run out of options. The given "mappedBy"
286 // setting is invalid.
287 if(pd == null)
288 throw new GrailsDomainException("Non-existent mapping property ["+mappingProperty+"] specified for property ["+property.getName()+"] in class ["+getClazz()+"]");
290 // Tie the properties together.
291 relatedClassPropertyType = pd.getPropertyType();
292 property.setReferencePropertyName(pd.getName());
294 else {
295 // if the related type has a relationships map it may be a many-to-many
296 // figure out if there is a many-to-many relationship defined
297 if( isRelationshipManyToMany(property, relatedClassType, relatedClassRelationships)) {
298 String relatedClassPropertyName = null;
299 // retrieve the relationship property
300 for(Iterator i = relatedClassRelationships.keySet().iterator();i.hasNext();) {
301 String currentKey = (String)i.next();
302 Class currentClass = (Class) relatedClassRelationships.get( currentKey );
303 if(currentClass.isAssignableFrom(getClazz())) {
304 relatedClassPropertyName = currentKey;
305 break;
309 // if there is one defined get the type
310 if(relatedClassPropertyName != null) {
311 relatedClassPropertyType = GrailsClassUtils.getPropertyType( relatedClassType, relatedClassPropertyName);
314 // otherwise figure out if there is a one-to-many relationship by retrieving any properties that are of the related type
315 // if there is more than one property then (for the moment) ignore the relationship
316 if(relatedClassPropertyType == null) {
317 PropertyDescriptor[] descriptors = GrailsClassUtils.getPropertiesOfType(relatedClassType, getClazz());
319 if(descriptors.length == 1) {
320 relatedClassPropertyType = descriptors[0].getPropertyType();
321 property.setReferencePropertyName(descriptors[0].getName());
323 else if(descriptors.length > 1) {
324 // try now to use the class name by convention
325 String classPropertyName = getPropertyName();
326 PropertyDescriptor pd = findProperty(descriptors, classPropertyName);
327 if(pd == null) {
328 throw new GrailsDomainException("Property ["+property.getName()+"] in class ["+getClazz()+"] is a bidirectional one-to-many with two possible properties on the inverse side. "+
329 "Either name one of the properties on other side of the relationship ["+classPropertyName+"] or use the 'mappedBy' static to define the property " +
330 "that the relationship is mapped with. Example: static mappedBy = ["+property.getName()+":'myprop']");
333 relatedClassPropertyType = pd.getPropertyType();
334 property.setReferencePropertyName(pd.getName());
339 establishRelationshipForSetToType(property,relatedClassPropertyType);
340 // if its a many-to-many figure out the owning side of the relationship
341 if(property.isManyToMany()) {
342 establishOwnerOfManyToMany(property, relatedClassType);
345 // otherwise set it to not persistent as you can't persist
346 // relationships to non-domain classes
347 else {
348 property.setPersistant(false);
351 else if(!Map.class.isAssignableFrom(property.getType())) {
352 // no relationship defined for set.
353 // set not persistent
354 property.setPersistant(false);
360 * Finds a property type is an array of descriptors for the given property name
362 * @param descriptors The descriptors
363 * @param propertyName The property name
364 * @return The Class or null
366 private PropertyDescriptor findProperty(PropertyDescriptor[] descriptors, String propertyName) {
367 PropertyDescriptor d = null;
368 for (int i = 0; i < descriptors.length; i++) {
369 PropertyDescriptor descriptor = descriptors[i];
370 if(descriptor.getName().equals(propertyName)) {
371 d = descriptor;
372 break;
375 return d;
379 * Find out if the relationship is a many-to-many
381 * @param property The property
382 * @param relatedClassType The related type
383 * @param relatedClassRelationships The related types relationships
384 * @return True if the relationship is a many-to-many
386 private boolean isRelationshipManyToMany(DefaultGrailsDomainClassProperty property, Class relatedClassType, Map relatedClassRelationships) {
387 return relatedClassRelationships != null &&
388 !relatedClassRelationships.isEmpty() &&
389 !relatedClassType.equals(property.getDomainClass().getClazz());
393 * Inspects a related classes' ownership settings against this properties class' ownership
394 * settings to find out who owns a many-to-many relationship
396 * @param property The property
397 * @param relatedClassType The related type
399 private void establishOwnerOfManyToMany(DefaultGrailsDomainClassProperty property, Class relatedClassType) {
400 Object related = BeanUtils.instantiateClass(relatedClassType);
401 Object relatedBelongsTo = GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(related, GrailsDomainClassProperty.BELONGS_TO);
402 boolean owningSide = false;
403 boolean relatedOwner = this.owners.contains(relatedClassType);
404 final Class propertyClass = property.getDomainClass().getClazz();
405 if(relatedBelongsTo instanceof Collection) {
406 owningSide = ((Collection)relatedBelongsTo).contains(propertyClass);
408 else if (relatedBelongsTo != null) {
409 owningSide = relatedBelongsTo.equals(propertyClass);
411 property.setOwningSide(owningSide);
412 if(relatedOwner && property.isOwningSide()) {
413 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.");
415 else if(!relatedOwner && !property.isOwningSide()) {
416 throw new GrailsDomainException("No owner defined between domain classes ["+propertyClass+"] and ["+relatedClassType+"] in a many-to-many relationship. Example: def belongsTo = "+relatedClassType.getName());
421 * Establishes whether the relationship is a bi-directional or uni-directional one-to-many
422 * and applies the appropriate settings to the specified property
424 * @param property The property to apply settings to
425 * @param relatedClassPropertyType The related type
427 private void establishRelationshipForSetToType(DefaultGrailsDomainClassProperty property, Class relatedClassPropertyType) {
429 if(relatedClassPropertyType == null) {
430 // uni-directional one-to-many
431 property.setOneToMany(true);
432 property.setBidirectional(false);
434 else if( Collection.class.isAssignableFrom(relatedClassPropertyType) ){
435 // many-to-many
436 property.setManyToMany(true);
437 property.setBidirectional(true);
439 else if(DomainClassArtefactHandler.isDomainClass(relatedClassPropertyType)) {
440 // bi-directional one-to-many
441 property.setOneToMany( true );
442 property.setBidirectional( true );
448 * Establish relationship with related domain class
450 * @param property Establishes a relationship between this class and the domain class property
452 private void establishDomainClassRelationship(DefaultGrailsDomainClassProperty property) {
453 Class propType = property.getType();
454 if(embedded.contains(property.getName())) {
455 property.setEmbedded(true);
456 return;
459 // establish relationship to type
460 Map relatedClassRelationships = GrailsDomainConfigurationUtil.getAssociationMap(propType);
461 Map mappedBy = GrailsDomainConfigurationUtil.getMappedByMap(propType);
464 Class relatedClassPropertyType = null;
466 // if there is a relationships map use that to find out
467 // whether it is mapped to a Set
468 if( relatedClassRelationships != null &&
469 !relatedClassRelationships.isEmpty() ) {
472 String relatedClassPropertyName = findOneToManyThatMatchesType(property, relatedClassRelationships);
473 PropertyDescriptor[] descriptors = GrailsClassUtils.getPropertiesOfType(getClazz(), property.getType());
475 // if there is only one property on many-to-one side of the relationship then
476 // try to establish if it is bidirectional
477 if(descriptors.length == 1 && isNotMappedToDifferentProperty(property,relatedClassPropertyName, mappedBy)) {
478 if(!StringUtils.isBlank(relatedClassPropertyName)) {
479 property.setReferencePropertyName(relatedClassPropertyName);
480 // get the type of the property
481 relatedClassPropertyType = GrailsClassUtils.getPropertyType( propType, relatedClassPropertyName );
484 // if there is more than one property on the many-to-one side then we need to either
485 // find out if there is a mappedBy property or whether a convention is used to decide
486 // on the mapping property
487 else if(descriptors.length > 1) {
488 if(mappedBy.containsValue(property.getName())) {
489 for (Iterator i = mappedBy.keySet().iterator(); i.hasNext();) {
490 String mappedByPropertyName = (String) i.next();
491 if(property.getName().equals(mappedBy.get(mappedByPropertyName))) {
492 Class mappedByRelatedType = (Class)relatedClassRelationships.get(mappedByPropertyName);
493 if(mappedByRelatedType != null && propType.isAssignableFrom(mappedByRelatedType))
494 relatedClassPropertyType = GrailsClassUtils.getPropertyType( propType, mappedByPropertyName );
498 else {
499 String classNameAsProperty = GrailsClassUtils.getPropertyName(propType);
500 if(property.getName().equals(classNameAsProperty) && !mappedBy.containsKey(relatedClassPropertyName)) {
501 relatedClassPropertyType = GrailsClassUtils.getPropertyType( propType, relatedClassPropertyName );
506 // otherwise retrieve all the properties of the type from the associated class
507 if(relatedClassPropertyType == null) {
508 PropertyDescriptor[] descriptors = GrailsClassUtils.getPropertiesOfType(propType, getClazz());
510 // if there is only one then the association is established
511 if(descriptors.length == 1) {
512 relatedClassPropertyType = descriptors[0].getPropertyType();
517 // establish relationship based on this type
518 establishDomainClassRelationshipToType( property, relatedClassPropertyType );
521 private boolean isNotMappedToDifferentProperty(GrailsDomainClassProperty property, String relatedClassPropertyName, Map mappedBy) {
522 String mappedByForRelation = (String)mappedBy.get(relatedClassPropertyName);
523 if(mappedByForRelation == null) return true;
524 else if(!property.getName().equals(mappedByForRelation)) return false;
525 return true;
528 private String findOneToManyThatMatchesType(DefaultGrailsDomainClassProperty property, Map relatedClassRelationships) {
529 String relatedClassPropertyName = null;
530 for(Iterator i = relatedClassRelationships.keySet().iterator();i.hasNext();) {
531 String currentKey = (String)i.next();
532 Class currentClass = (Class)relatedClassRelationships.get( currentKey );
534 if(property.getDomainClass().getClazz().getName().equals( currentClass.getName() )) {
535 relatedClassPropertyName = currentKey;
537 break;
540 return relatedClassPropertyName;
543 private void establishDomainClassRelationshipToType(DefaultGrailsDomainClassProperty property, Class relatedClassPropertyType) {
544 // uni-directional one-to-one
545 if(relatedClassPropertyType == null) {
546 property.setOneToOne(true);
547 property.setBidirectional(false);
549 // bi-directional many-to-one
550 else if(Collection.class.isAssignableFrom(relatedClassPropertyType)||Map.class.isAssignableFrom(relatedClassPropertyType)) {
551 property.setManyToOne(true);
552 property.setBidirectional(true);
554 // bi-directional one-to-one
555 else if(DomainClassArtefactHandler.isDomainClass(relatedClassPropertyType)) {
556 property.setOneToOne(true);
557 if(!getClazz().equals(relatedClassPropertyType))
558 property.setBidirectional(true);
563 public boolean isOwningClass(Class domainClass) {
564 return this.owners.contains(domainClass);
567 /* (non-Javadoc)
568 * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getProperties()
570 public GrailsDomainClassProperty[] getProperties() {
571 return this.properties;
574 /* (non-Javadoc)
575 * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getIdentifier()
577 public GrailsDomainClassProperty getIdentifier() {
578 return this.identifier;
581 /* (non-Javadoc)
582 * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getVersion()
584 public GrailsDomainClassProperty getVersion() {
585 return this.version;
589 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#getPersistantProperties()
590 * @deprecated
592 public GrailsDomainClassProperty[] getPersistantProperties() {
593 return this.persistantProperties;
596 public GrailsDomainClassProperty[] getPersistentProperties() {
597 return this.persistantProperties;
600 /* (non-Javadoc)
601 * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getPropertyByName(java.lang.String)
603 public GrailsDomainClassProperty getPropertyByName(String name) {
604 if(this.propertyMap.containsKey(name)) {
605 return (GrailsDomainClassProperty)this.propertyMap.get(name);
607 else {
608 throw new InvalidPropertyException("No property found for name ["+name+"] for class ["+getClazz()+"]");
611 /* (non-Javadoc)
612 * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#getFieldName(java.lang.String)
614 public String getFieldName(String propertyName) {
615 return getPropertyByName(propertyName).getFieldName();
618 /* (non-Javadoc)
619 * @see org.codehaus.groovy.grails.commons.AbstractGrailsClass#getName()
621 public String getName() {
622 return ClassUtils.getShortClassName(super.getName());
624 /* (non-Javadoc)
625 * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#isOneToMany(java.lang.String)
627 public boolean isOneToMany(String propertyName) {
628 return getPropertyByName(propertyName).isOneToMany();
630 /* (non-Javadoc)
631 * @see org.codehaus.groovy.grails.domain.GrailsDomainClass#isManyToOne(java.lang.String)
633 public boolean isManyToOne(String propertyName) {
634 return getPropertyByName(propertyName).isManyToOne();
637 protected Object getPropertyOrStaticPropertyOrFieldValue(String name, Class type) {
638 return super.getPropertyOrStaticPropertyOrFieldValue(name,type);
640 /* (non-Javadoc)
641 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#getRelationshipType(java.lang.String)
643 public Class getRelatedClassType(String propertyName) {
644 return (Class)this.relationshipMap.get(propertyName);
647 /* (non-Javadoc)
648 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#getPropertyName()
650 public String getPropertyName() {
651 return GrailsClassUtils.getPropertyNameRepresentation(getClazz());
654 /* (non-Javadoc)
655 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#isBidirectional()
657 public boolean isBidirectional(String propertyName) {
658 return getPropertyByName(propertyName).isBidirectional();
661 /* (non-Javadoc)
662 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#getConstraints()
664 public Map getConstrainedProperties() {
665 return Collections.unmodifiableMap(this.constraints);
667 /* (non-Javadoc)
668 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#getValidator()
670 public Validator getValidator() {
671 return this.validator;
674 /* (non-Javadoc)
675 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#setValidator(Validator validator)
677 public void setValidator(Validator validator) {
678 this.validator = validator;
681 /* (non-Javadoc)
682 * @see org.codehaus.groovy.grails.commons.GrailsDomainClass#getMappedBy()
684 public String getMappingStrategy() {
685 return this.mappingStrategy;
688 public boolean isRoot() {
689 return this.root;
692 public Set getSubClasses() {
693 return this.subClasses;
696 public void refreshConstraints() {
697 try {
698 this.constraints = GrailsDomainConfigurationUtil.evaluateConstraints(getReference().getWrappedInstance(), this.persistantProperties);
699 } catch (IntrospectionException e) {
700 LOG.error("Error reading class ["+getClazz()+"] constraints: " +e .getMessage(), e);
704 public Map getMappedBy() {
705 return mappedBy;
708 public boolean hasPersistentProperty(String propertyName) {
709 for (int i = 0; i < persistantProperties.length; i++) {
710 GrailsDomainClassProperty persistantProperty = persistantProperties[i];
711 if(persistantProperty.getName().equals(propertyName)) return true;
713 return false;
716 public void setMappingStrategy(String strategy) {
717 this.mappingStrategy = strategy;