1 /*******************************************************************************
2  * Copyright (c) 2008, 2016 Matthew Hall and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     Matthew Hall - initial API and implementation (bug 194734)
13  *     Matthew Hall - bug 195222, 247997, 261843, 264307
14  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 488364
15  ******************************************************************************/
16 
17 package org.eclipse.core.databinding.beans.typed;
18 
19 import java.beans.PropertyDescriptor;
20 import java.util.ArrayList;
21 import java.util.List;
22 
23 import org.eclipse.core.databinding.beans.IBeanListProperty;
24 import org.eclipse.core.databinding.beans.IBeanMapProperty;
25 import org.eclipse.core.databinding.beans.IBeanSetProperty;
26 import org.eclipse.core.databinding.beans.IBeanValueProperty;
27 import org.eclipse.core.databinding.property.list.IListProperty;
28 import org.eclipse.core.databinding.property.map.IMapProperty;
29 import org.eclipse.core.databinding.property.set.ISetProperty;
30 import org.eclipse.core.databinding.property.value.IValueProperty;
31 import org.eclipse.core.internal.databinding.beans.AnonymousBeanListProperty;
32 import org.eclipse.core.internal.databinding.beans.AnonymousBeanMapProperty;
33 import org.eclipse.core.internal.databinding.beans.AnonymousBeanSetProperty;
34 import org.eclipse.core.internal.databinding.beans.AnonymousBeanValueProperty;
35 import org.eclipse.core.internal.databinding.beans.BeanListProperty;
36 import org.eclipse.core.internal.databinding.beans.BeanListPropertyDecorator;
37 import org.eclipse.core.internal.databinding.beans.BeanMapProperty;
38 import org.eclipse.core.internal.databinding.beans.BeanMapPropertyDecorator;
39 import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper;
40 import org.eclipse.core.internal.databinding.beans.BeanSetProperty;
41 import org.eclipse.core.internal.databinding.beans.BeanSetPropertyDecorator;
42 import org.eclipse.core.internal.databinding.beans.BeanValueProperty;
43 import org.eclipse.core.internal.databinding.beans.BeanValuePropertyDecorator;
44 
45 /**
46  * A factory for creating properties for Java objects that conform to the
47  * <a href="http://java.sun.com/products/javabeans/docs/spec.html">JavaBean
48  * specification</a> for bound properties.
49  * <p>
50  * This class is a new version of the deprecated class with the same name in the
51  * parent package. The difference is that this class returns typed property
52  * objects. This class is located in its own package to be able to coexist with
53  * the old version while having the same name.
54  *
55  * @since 1.5
56  */
57 public class BeanProperties {
58 	/**
59 	 * Returns a value property for the given property name of an arbitrary bean
60 	 * class. Objects lacking the named property are treated the same as if the
61 	 * property always contains null.
62 	 *
63 	 * @param propertyName
64 	 *            the property name. May be nested e.g. "parent.name"
65 	 * @return a value property for the given property name of an arbitrary bean
66 	 *         class.
67 	 */
value(String propertyName)68 	public static <S, T> IBeanValueProperty<S, T> value(String propertyName) {
69 		return value(null, propertyName, null);
70 	}
71 
72 	/**
73 	 * Returns a value property for the given property name of an arbitrary bean
74 	 * class. Objects lacking the named property are treated the same as if the
75 	 * property always contains null.
76 	 *
77 	 * @param propertyName
78 	 *            the property name. May be nested e.g. "parent.name"
79 	 * @param valueType
80 	 *            the value type of the returned value property
81 	 * @return a value property for the given property name of an arbitrary bean
82 	 *         class.
83 	 */
value(String propertyName, Class<T> valueType)84 	public static <S, T> IBeanValueProperty<S, T> value(String propertyName, Class<T> valueType) {
85 		return value(null, propertyName, valueType);
86 	}
87 
88 	/**
89 	 * Returns a value property for the given property name of the given bean
90 	 * class.
91 	 *
92 	 * @param beanClass
93 	 *            the bean class
94 	 * @param propertyName
95 	 *            the property name. May be nested e.g. "parent.name"
96 	 * @return a value property for the given property name of the given bean
97 	 *         class.
98 	 */
value(Class<S> beanClass, String propertyName)99 	public static <S, T> IBeanValueProperty<S, T> value(Class<S> beanClass, String propertyName) {
100 		return value(beanClass, propertyName, null);
101 	}
102 
103 	/**
104 	 * Returns a value property for the given property name of the given bean
105 	 * class.
106 	 *
107 	 * @param beanClass
108 	 *            the bean class
109 	 * @param propertyName
110 	 *            the property name. May be nested e.g. "parent.name"
111 	 * @param valueType
112 	 *            the value type of the returned value property
113 	 * @return a value property for the given property name of the given bean
114 	 *         class.
115 	 */
116 	@SuppressWarnings("unchecked")
value(Class<S> beanClass, String propertyName, Class<T> valueType)117 	public static <S, T> IBeanValueProperty<S, T> value(Class<S> beanClass, String propertyName, Class<T> valueType) {
118 		String[] propertyNames = split(propertyName);
119 		if (propertyNames.length > 1)
120 			valueType = null;
121 
122 		PropertyDescriptor propertyDescriptor;
123 		IValueProperty<S, T> property;
124 		if (beanClass == null) {
125 			propertyDescriptor = null;
126 			property = new AnonymousBeanValueProperty<>(propertyNames[0], valueType);
127 		} else {
128 			propertyDescriptor = BeanPropertyHelper.getPropertyDescriptor(beanClass, propertyNames[0]);
129 			property = new BeanValueProperty<>(propertyDescriptor, valueType);
130 		}
131 
132 		IBeanValueProperty<S, T> beanProperty = new BeanValuePropertyDecorator<>(property, propertyDescriptor);
133 		for (int i = 1; i < propertyNames.length; i++) {
134 			beanProperty = (IBeanValueProperty<S, T>) beanProperty.value(propertyNames[i]);
135 		}
136 		return beanProperty;
137 	}
138 
split(String propertyName)139 	private static String[] split(String propertyName) {
140 		if (propertyName.indexOf('.') == -1)
141 			return new String[] { propertyName };
142 		List<String> propertyNames = new ArrayList<>();
143 		int index;
144 		while ((index = propertyName.indexOf('.')) != -1) {
145 			propertyNames.add(propertyName.substring(0, index));
146 			propertyName = propertyName.substring(index + 1);
147 		}
148 		propertyNames.add(propertyName);
149 		return propertyNames.toArray(new String[propertyNames.size()]);
150 	}
151 
152 	/**
153 	 * Returns a value property array for the given property names of the given
154 	 * bean class.
155 	 *
156 	 * @param beanClass
157 	 *            the bean class
158 	 * @param propertyNames
159 	 *            defines the property names. May be nested e.g. "parent.name"
160 	 * @return a value property array for the given property names of the given
161 	 *         bean class.
162 	 */
values(Class<S> beanClass, String... propertyNames)163 	public static <S, T> IBeanValueProperty<S, T>[] values(Class<S> beanClass, String... propertyNames) {
164 		@SuppressWarnings("unchecked")
165 		IBeanValueProperty<S, T>[] properties = new IBeanValueProperty[propertyNames.length];
166 		for (int i = 0; i < properties.length; i++)
167 			properties[i] = value(beanClass, propertyNames[i], null);
168 		return properties;
169 	}
170 
171 	/**
172 	 * Returns a value property array for the given property names of an
173 	 * arbitrary bean class.
174 	 *
175 	 * @param propertyNames
176 	 *            defines the property names. May be nested e.g. "parent.name"
177 	 * @return a value property array for the given property names of the given
178 	 *         bean class.
179 	 */
values(String... propertyNames)180 	public static <S, T> IBeanValueProperty<S, T>[] values(String... propertyNames) {
181 		return values(null, propertyNames);
182 	}
183 
184 	/**
185 	 * Returns a set property for the given property name of an arbitrary bean
186 	 * class. Objects lacking the named property are treated the same as if the
187 	 * property always contains an empty set.
188 	 *
189 	 * @param propertyName
190 	 *            the property name
191 	 * @return a set property for the given property name of an arbitrary bean
192 	 *         class.
193 	 */
set(String propertyName)194 	public static <S, E> IBeanSetProperty<S, E> set(String propertyName) {
195 		return set(null, propertyName, null);
196 	}
197 
198 	/**
199 	 * Returns a set property for the given property name of an arbitrary bean
200 	 * class. Objects lacking the named property are treated the same as if the
201 	 * property always contains an empty set.
202 	 *
203 	 * @param propertyName
204 	 *            the property name
205 	 * @param elementType
206 	 *            the element type of the returned set property
207 	 * @return a set property for the given property name of an arbitrary bean
208 	 *         class.
209 	 */
set(String propertyName, Class<E> elementType)210 	public static <S, E> IBeanSetProperty<S, E> set(String propertyName, Class<E> elementType) {
211 		return set(null, propertyName, elementType);
212 	}
213 
214 	/**
215 	 * Returns a set property for the given property name of the given bean
216 	 * class.
217 	 *
218 	 * @param beanClass
219 	 *            the bean class
220 	 * @param propertyName
221 	 *            the property name
222 	 * @return a set property for the given property name of the given bean
223 	 *         class.
224 	 */
set(Class<S> beanClass, String propertyName)225 	public static <S, E> IBeanSetProperty<S, E> set(Class<S> beanClass, String propertyName) {
226 		return set(beanClass, propertyName, null);
227 	}
228 
229 	/**
230 	 * Returns a set property for the given property name of the given bean
231 	 * class.
232 	 *
233 	 * @param beanClass
234 	 *            the bean class
235 	 * @param propertyName
236 	 *            the property name
237 	 * @param elementType
238 	 *            the element type of the returned set property
239 	 * @return a set property for the given property name of the given bean
240 	 *         class.
241 	 */
set(Class<S> beanClass, String propertyName, Class<E> elementType)242 	public static <S, E> IBeanSetProperty<S, E> set(Class<S> beanClass, String propertyName, Class<E> elementType) {
243 		PropertyDescriptor propertyDescriptor;
244 		ISetProperty<S, E> property;
245 		if (beanClass == null) {
246 			propertyDescriptor = null;
247 			property = new AnonymousBeanSetProperty<>(propertyName, elementType);
248 		} else {
249 			propertyDescriptor = BeanPropertyHelper.getPropertyDescriptor(
250 					beanClass, propertyName);
251 			property = new BeanSetProperty<>(propertyDescriptor, elementType);
252 		}
253 		return new BeanSetPropertyDecorator<>(property, propertyDescriptor);
254 	}
255 
256 	/**
257 	 * Returns a list property for the given property name of an arbitrary bean
258 	 * class. Objects lacking the named property are treated the same as if the
259 	 * property always contains an empty list.
260 	 *
261 	 * @param propertyName
262 	 *            the property name
263 	 * @return a list property for the given property name of an arbitrary bean
264 	 *         class.
265 	 */
list(String propertyName)266 	public static <S, E> IBeanListProperty<S, E> list(String propertyName) {
267 		return list(null, propertyName, null);
268 	}
269 
270 	/**
271 	 * Returns a list property for the given property name of an arbitrary bean
272 	 * class. Objects lacking the named property are treated the same as if the
273 	 * property always contains an empty list.
274 	 *
275 	 * @param propertyName
276 	 *            the property name
277 	 * @param elementType
278 	 *            the element type of the returned list property
279 	 * @return a list property for the given property name of the given bean
280 	 *         class.
281 	 */
list(String propertyName, Class<E> elementType)282 	public static <S, E> IBeanListProperty<S, E> list(String propertyName, Class<E> elementType) {
283 		return list(null, propertyName, elementType);
284 	}
285 
286 	/**
287 	 * Returns a list property for the given property name of the given bean
288 	 * class.
289 	 *
290 	 * @param beanClass
291 	 *            the bean class
292 	 * @param propertyName
293 	 *            the property name
294 	 * @return a list property for the given property name of the given bean
295 	 *         class.
296 	 */
list(Class<S> beanClass, String propertyName)297 	public static <S, E> IBeanListProperty<S, E> list(Class<S> beanClass, String propertyName) {
298 		return list(beanClass, propertyName, null);
299 	}
300 
301 	/**
302 	 * Returns a list property for the given property name of the given bean
303 	 * class.
304 	 *
305 	 * @param beanClass
306 	 *            the bean class
307 	 * @param propertyName
308 	 *            the property name
309 	 * @param elementType
310 	 *            the element type of the returned list property
311 	 * @return a list property for the given property name of the given bean
312 	 *         class.
313 	 */
list(Class<S> beanClass, String propertyName, Class<E> elementType)314 	public static <S, E> IBeanListProperty<S, E> list(Class<S> beanClass, String propertyName, Class<E> elementType) {
315 		PropertyDescriptor propertyDescriptor;
316 		IListProperty<S, E> property;
317 		if (beanClass == null) {
318 			propertyDescriptor = null;
319 			property = new AnonymousBeanListProperty<>(propertyName, elementType);
320 		} else {
321 			propertyDescriptor = BeanPropertyHelper.getPropertyDescriptor(
322 					beanClass, propertyName);
323 			property = new BeanListProperty<>(propertyDescriptor, elementType);
324 		}
325 		return new BeanListPropertyDecorator<>(property, propertyDescriptor);
326 	}
327 
328 	/**
329 	 * Returns a map property for the given property name of an arbitrary bean
330 	 * class. Objects lacking the named property are treated the same as if the
331 	 * property always contains an empty map.
332 	 *
333 	 * @param propertyName
334 	 *            the property name
335 	 * @return a map property for the given property name of an arbitrary bean
336 	 *         class.
337 	 */
map(String propertyName)338 	public static <S, K, V> IBeanMapProperty<S, K, V> map(String propertyName) {
339 		return map(null, propertyName, null, null);
340 	}
341 
342 	/**
343 	 * Returns a map property for the given property name of an arbitrary bean
344 	 * class. Objects lacking the named property are treated the same as if the
345 	 * property always contains an empty map.
346 	 *
347 	 * @param propertyName
348 	 *            the property name
349 	 * @param keyType
350 	 *            the key type for the returned map property
351 	 * @param valueType
352 	 *            the value type for the returned map property
353 	 * @return a map property for the given property name of an arbitrary bean
354 	 *         class.
355 	 */
map(String propertyName, Class<K> keyType, Class<V> valueType)356 	public static <S, K, V> IBeanMapProperty<S, K, V> map(String propertyName, Class<K> keyType, Class<V> valueType) {
357 		return map(null, propertyName, keyType, valueType);
358 	}
359 
360 	/**
361 	 * Returns a map property for the given property name of the given bean
362 	 * class.
363 	 *
364 	 * @param beanClass
365 	 *            the bean class
366 	 * @param propertyName
367 	 *            the property name
368 	 * @return a map property for the given property name of the given bean
369 	 *         class.
370 	 */
map(Class<S> beanClass, String propertyName)371 	public static <S, K, V> IBeanMapProperty<S, K, V> map(Class<S> beanClass, String propertyName) {
372 		return map(beanClass, propertyName, null, null);
373 	}
374 
375 	/**
376 	 * Returns a map property for the given property name of the given bean
377 	 * class.
378 	 *
379 	 * @param beanClass
380 	 *            the bean class
381 	 * @param propertyName
382 	 *            the property name
383 	 * @param keyType
384 	 *            the key type for the returned map property
385 	 * @param valueType
386 	 *            the value type for the returned map property
387 	 * @return a map property for the given property name of the given bean
388 	 *         class.
389 	 */
map(Class<S> beanClass, String propertyName, Class<K> keyType, Class<V> valueType)390 	public static <S, K, V> IBeanMapProperty<S, K, V> map(Class<S> beanClass, String propertyName, Class<K> keyType,
391 			Class<V> valueType) {
392 		PropertyDescriptor propertyDescriptor;
393 		IMapProperty<S, K, V> property;
394 		if (beanClass == null) {
395 			propertyDescriptor = null;
396 			property = new AnonymousBeanMapProperty<>(propertyName, keyType, valueType);
397 		} else {
398 			propertyDescriptor = BeanPropertyHelper.getPropertyDescriptor(beanClass, propertyName);
399 			property = new BeanMapProperty<>(propertyDescriptor, keyType, valueType);
400 		}
401 		return new BeanMapPropertyDecorator<>(property, propertyDescriptor);
402 	}
403 }
404