KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > config > PropertyPathFactoryBean


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */

16
17 package org.springframework.beans.factory.config;
18
19 import org.springframework.beans.BeanWrapper;
20 import org.springframework.beans.BeanWrapperImpl;
21 import org.springframework.beans.BeansException;
22 import org.springframework.beans.FatalBeanException;
23 import org.springframework.beans.factory.BeanFactory;
24 import org.springframework.beans.factory.BeanFactoryAware;
25 import org.springframework.beans.factory.BeanFactoryUtils;
26 import org.springframework.beans.factory.BeanNameAware;
27 import org.springframework.beans.factory.FactoryBean;
28 import org.springframework.util.StringUtils;
29
30 /**
31  * {@link FactoryBean} that evaluates a property path on a given target object.
32  *
33  * <p>The target object can be specified directly or via a bean name.
34  *
35  * <p>Usage examples:
36  *
37  * <pre class="code">&lt;!-- target bean to be referenced by name --&gt;
38  * &lt;bean id="tb" class="org.springframework.beans.TestBean" singleton="false"&gt;
39  * &lt;property name="age" value="10"/&gt;
40  * &lt;property name="spouse"&gt;
41  * &lt;bean class="org.springframework.beans.TestBean"&gt;
42  * &lt;property name="age" value="11"/&gt;
43  * &lt;/bean&gt;
44  * &lt;/property&gt;
45  * &lt;/bean&gt;
46  *
47  * &lt;!-- will result in 12, which is the value of property 'age' of the inner bean --&gt;
48  * &lt;bean id="propertyPath1" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"&gt;
49  * &lt;property name="targetObject"&gt;
50  * &lt;bean class="org.springframework.beans.TestBean"&gt;
51  * &lt;property name="age" value="12"/&gt;
52  * &lt;/bean&gt;
53  * &lt;/property&gt;
54  * &lt;property name="propertyPath" value="age"/&gt;
55  * &lt;/bean&gt;
56  *
57  * &lt;!-- will result in 11, which is the value of property 'spouse.age' of bean 'tb' --&gt;
58  * &lt;bean id="propertyPath2" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"&gt;
59  * &lt;property name="targetBeanName" value="tb"/&gt;
60  * &lt;property name="propertyPath" value="spouse.age"/&gt;
61  * &lt;/bean&gt;
62  *
63  * &lt;!-- will result in 10, which is the value of property 'age' of bean 'tb' --&gt;
64  * &lt;bean id="tb.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/&gt;</pre>
65  *
66  * <p>If you are using Spring 2.0 and XML Schema support in your configuration file(s),
67  * you can also use the following style of configuration for property path access.
68  * (See also the appendix entitled 'XML Schema-based configuration' in the Spring
69  * reference manual for more examples.)
70  *
71  * <pre class="code"> &lt;!-- will result in 10, which is the value of property 'age' of bean 'tb' --&gt;
72  * &lt;util:property-path id="name" path="testBean.age"/&gt;</pre>
73  *
74  * Thanks to Matthias Ernst for the suggestion and initial prototype!
75  *
76  * @author Juergen Hoeller
77  * @since 1.1.2
78  * @see #setTargetObject
79  * @see #setTargetBeanName
80  * @see #setPropertyPath
81  */

82 public class PropertyPathFactoryBean implements FactoryBean, BeanNameAware, BeanFactoryAware {
83
84     private BeanWrapper targetBeanWrapper;
85
86     private String JavaDoc targetBeanName;
87
88     private String JavaDoc propertyPath;
89
90     private Class JavaDoc resultType;
91
92     private String JavaDoc beanName;
93
94     private BeanFactory beanFactory;
95
96
97     /**
98      * Specify a target object to apply the property path to.
99      * Alternatively, specify a target bean name.
100      * @param targetObject a target object, for example a bean reference
101      * or an inner bean
102      * @see #setTargetBeanName
103      */

104     public void setTargetObject(Object JavaDoc targetObject) {
105         this.targetBeanWrapper = new BeanWrapperImpl(targetObject);
106     }
107
108     /**
109      * Specify the name of a target bean to apply the property path to.
110      * Alternatively, specify a target object directly.
111      * @param targetBeanName the bean name to be looked up in the
112      * containing bean factory (e.g. "testBean")
113      * @see #setTargetObject
114      */

115     public void setTargetBeanName(String JavaDoc targetBeanName) {
116         this.targetBeanName = StringUtils.trimAllWhitespace(targetBeanName);
117     }
118
119     /**
120      * Specify the property path to apply to the target.
121      * @param propertyPath the property path, potentially nested
122      * (e.g. "age" or "spouse.age")
123      */

124     public void setPropertyPath(String JavaDoc propertyPath) {
125         this.propertyPath = StringUtils.trimAllWhitespace(propertyPath);
126     }
127
128     /**
129      * Specify the type of the result from evaluating the property path.
130      * <p>Note: This is not necessary for directly specified target objects
131      * or singleton target beans, where the type can be determined through
132      * introspection. Just specify this in case of a prototype target,
133      * provided that you need matching by type (for example, for autowiring).
134      * @param resultType the result type, for example "java.lang.Integer"
135      */

136     public void setResultType(Class JavaDoc resultType) {
137         this.resultType = resultType;
138     }
139
140     /**
141      * The bean name of this PropertyPathFactoryBean will be interpreted
142      * as "beanName.property" pattern, if neither "targetObject" nor
143      * "targetBeanName" nor "propertyPath" have been specified.
144      * This allows for concise bean definitions with just an id/name.
145      */

146     public void setBeanName(String JavaDoc beanName) {
147         this.beanName = StringUtils.trimAllWhitespace(BeanFactoryUtils.originalBeanName(beanName));
148     }
149
150
151     public void setBeanFactory(BeanFactory beanFactory) {
152         this.beanFactory = beanFactory;
153
154         if (this.targetBeanWrapper != null && this.targetBeanName != null) {
155             throw new IllegalArgumentException JavaDoc("Specify either targetObject or targetBeanName, not both");
156         }
157
158         if (this.targetBeanWrapper == null && this.targetBeanName == null) {
159             if (this.propertyPath != null) {
160                 throw new IllegalArgumentException JavaDoc(
161                     "Specify targetObject or targetBeanName in combination with propertyPath");
162             }
163
164             // No other properties specified: check bean name.
165
int dotIndex = this.beanName.indexOf('.');
166             if (dotIndex == -1) {
167                 throw new IllegalArgumentException JavaDoc(
168                     "Neither targetObject nor targetBeanName specified, and PropertyPathFactoryBean " +
169                     "bean name '" + this.beanName + "' does not follow 'beanName.property' syntax");
170             }
171             this.targetBeanName = this.beanName.substring(0, dotIndex);
172             this.propertyPath = this.beanName.substring(dotIndex + 1);
173         }
174
175         else if (this.propertyPath == null) {
176             // either targetObject or targetBeanName specified
177
throw new IllegalArgumentException JavaDoc("propertyPath is required");
178         }
179
180         if (this.targetBeanWrapper == null && this.beanFactory.isSingleton(this.targetBeanName)) {
181             // Eagerly fetch singleton target bean, and determine result type.
182
this.targetBeanWrapper = new BeanWrapperImpl(this.beanFactory.getBean(this.targetBeanName));
183             this.resultType = this.targetBeanWrapper.getPropertyType(this.propertyPath);
184         }
185     }
186
187
188     public Object JavaDoc getObject() throws BeansException {
189         BeanWrapper target = this.targetBeanWrapper;
190         if (target == null) {
191             // fetch prototype target bean
192
target = new BeanWrapperImpl(this.beanFactory.getBean(this.targetBeanName));
193         }
194
195         Object JavaDoc value = target.getPropertyValue(this.propertyPath);
196         if (value == null) {
197             throw new FatalBeanException("PropertyPathFactoryBean is not allowed to return null, " +
198                 "but property value for path '" + this.propertyPath + "' is null");
199         }
200         return value;
201     }
202
203     public Class JavaDoc getObjectType() {
204         return this.resultType;
205     }
206
207     /**
208      * While this FactoryBean will often be used for singleton targets,
209      * the invoked getters for the property path might return a new object
210      * for each call, so we have to assume that we're not returning the
211      * same object for each getObject() call.
212      */

213     public boolean isSingleton() {
214         return false;
215     }
216
217 }
218
Popular Tags