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