2 * Copyright 2004-2005 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.codehaus
.groovy
.grails
.commons
;
18 import groovy
.lang
.GroovyObject
;
19 import groovy
.lang
.GroovySystem
;
20 import groovy
.lang
.MetaClass
;
21 import org
.apache
.commons
.lang
.ClassUtils
;
22 import org
.apache
.commons
.lang
.StringUtils
;
23 import org
.codehaus
.groovy
.grails
.exceptions
.NewInstanceCreationException
;
24 import org
.codehaus
.groovy
.runtime
.DefaultGroovyMethods
;
25 import org
.springframework
.beans
.BeanWrapper
;
26 import org
.springframework
.beans
.BeanWrapperImpl
;
28 import java
.lang
.reflect
.Constructor
;
29 import java
.lang
.reflect
.InvocationTargetException
;
33 * Abstract base class for Grails types that provides common functionality for
34 * evaluating conventions within classes
36 * @author Steven Devijver
37 * @author Graeme Rocher
41 * Created: Jul 2, 2005
43 public abstract class AbstractGrailsClass
implements GrailsClass
{
47 private Class clazz
= null;
48 private String fullName
= null;
49 private String name
= null;
50 private String packageName
= null;
51 private BeanWrapper reference
= null;
52 private String naturalName
;
53 private String shortName
;
54 private MetaClass metaClass
;
59 * <p>Contructor to be used by all child classes to create a
60 * new instance and get the name right.
62 * @param clazz the Grails class
63 * @param trailingName the trailing part of the name for this class type
65 public AbstractGrailsClass(Class clazz
, String trailingName
) {
69 this.reference
= new BeanWrapperImpl(newInstance());
70 this.fullName
= clazz
.getName();
71 this.packageName
= ClassUtils
.getPackageName(clazz
);
72 this.naturalName
= GrailsClassUtils
.getNaturalName(clazz
.getName());
73 this.shortName
= getShortClassname(clazz
);
74 this.name
= GrailsClassUtils
.getLogicalName(clazz
, trailingName
);
77 public String
getShortName() {
78 return this.shortName
;
81 private void setClazz(Class clazz
) {
83 throw new IllegalArgumentException("Clazz parameter should not be null");
88 public Class
getClazz() {
92 public Object
newInstance() {
94 Constructor defaultConstructor
= getClazz().getDeclaredConstructor(new Class
[]{});
95 if(!defaultConstructor
.isAccessible()) defaultConstructor
.setAccessible(true);
96 return defaultConstructor
.newInstance(new Object
[]{});
97 } catch (Exception e
) {
98 Throwable targetException
= null;
99 if (e
instanceof InvocationTargetException
) {
100 targetException
= ((InvocationTargetException
)e
).getTargetException();
104 throw new NewInstanceCreationException("Could not create a new instance of class [" + getClazz().getName() + "]!", targetException
);
108 public String
getName() {
112 public String
getNaturalName() {
113 return this.naturalName
;
116 public String
getFullName() {
117 return this.fullName
;
120 public String
getPropertyName() {
121 return GrailsClassUtils
.getPropertyNameRepresentation(getShortName());
124 public String
getLogicalPropertyName() {
126 final String logicalName
= getName();
127 if(StringUtils
.isBlank(logicalName
)) {
128 return GrailsClassUtils
.getPropertyNameRepresentation(getShortName());
130 return GrailsClassUtils
.getPropertyNameRepresentation(logicalName
);
133 public String
getPackageName() {
134 return this.packageName
;
137 private static String
getShortClassname(Class clazz
) {
138 return ClassUtils
.getShortClassName(clazz
);
142 * <p>The reference instance is used to get configured property values.
144 * @return BeanWrapper instance that holds reference
146 public BeanWrapper
getReference() {
147 Object obj
= this.reference
.getWrappedInstance();
148 if(obj
instanceof GroovyObject
) {
149 ((GroovyObject
)obj
).setMetaClass(GroovySystem
.getMetaClassRegistry().getMetaClass(getClazz()));
151 return this.reference
;
155 * <p>Looks for a property of the reference instance with a given name and type.</p>
156 * <p>If found its value is returned. We follow the Java bean conventions with augmentation for groovy support
157 * and static fields/properties. We will therefore match, in this order:
160 * <li>Standard public bean property (with getter or just public field, using normal introspection)
161 * <li>Public static property with getter method
162 * <li>Public static field
166 * @return property value or null if no property or static field was found
168 protected Object
getPropertyOrStaticPropertyOrFieldValue(String name
, Class type
) {
169 BeanWrapper ref
= getReference();
171 if (ref
.isReadableProperty(name
)) {
172 value
= ref
.getPropertyValue(name
);
174 else if (GrailsClassUtils
.isPublicField(ref
.getWrappedInstance(), name
))
176 value
= GrailsClassUtils
.getFieldValue(ref
.getWrappedInstance(), name
);
180 value
= GrailsClassUtils
.getStaticPropertyValue(clazz
, name
);
182 if ((value
!= null) && GrailsClassUtils
.isGroovyAssignableFrom( type
, value
.getClass())) {
189 * Get the value of the named property, with support for static properties in both Java and Groovy classes
190 * (which as of Groovy JSR 1.0 RC 01 only have getters in the metaClass)
193 * @return The property value or null
195 public Object
getPropertyValue(String name
, Class type
) {
197 // Handle standard java beans normal or static properties
198 BeanWrapper ref
= getReference();
200 if (ref
.isReadableProperty(name
)) {
201 value
= ref
.getPropertyValue(name
);
205 Object inst
= ref
.getWrappedInstance();
206 if (inst
instanceof GroovyObject
)
208 final Map properties
= DefaultGroovyMethods
.getProperties(inst
);
209 if(properties
.containsKey(name
)) {
210 value
= properties
.get(name
);
215 if(value
!= null && (type
.isAssignableFrom(value
.getClass())
216 || GrailsClassUtils
.isMatchBetweenPrimativeAndWrapperTypes(type
, value
.getClass()))) {
226 * @see org.codehaus.groovy.grails.commons.GrailsClass#getPropertyValue(java.lang.String)
228 public Object
getPropertyValue(String name
) {
229 return getPropertyOrStaticPropertyOrFieldValue(name
, Object
.class);
235 * @see org.codehaus.groovy.grails.commons.GrailsClass#hasProperty(java.lang.String)
237 public boolean hasProperty(String name
) {
238 return getReference().isReadableProperty(name
);
242 * @return the metaClass
244 public MetaClass
getMetaClass() {
245 return GrailsClassUtils
.getExpandoMetaClass(clazz
);
248 public String
toString() {
249 return "Artefact > " + getName();