Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

MethodProperty.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.data.util;
  5. import java.io.IOException;
  6. import java.lang.reflect.Constructor;
  7. import java.lang.reflect.InvocationTargetException;
  8. import java.lang.reflect.Method;
  9. import java.util.logging.Level;
  10. import java.util.logging.Logger;
  11. import com.vaadin.data.Property;
  12. import com.vaadin.util.SerializerHelper;
  13. /**
  14. * <p>
  15. * Proxy class for creating Properties from pairs of getter and setter methods
  16. * of a Bean property. An instance of this class can be thought as having been
  17. * attached to a field of an object. Accessing the object through the Property
  18. * interface directly manipulates the underlying field.
  19. * </p>
  20. *
  21. * <p>
  22. * It's assumed that the return value returned by the getter method is
  23. * assignable to the type of the property, and the setter method parameter is
  24. * assignable to that value.
  25. * </p>
  26. *
  27. * <p>
  28. * A valid getter method must always be available, but instance of this class
  29. * can be constructed with a <code>null</code> setter method in which case the
  30. * resulting MethodProperty is read-only.
  31. * </p>
  32. *
  33. * <p>
  34. * MethodProperty implements Property.ValueChangeNotifier, but does not
  35. * automatically know whether or not the getter method will actually return a
  36. * new value - value change listeners are always notified when setValue is
  37. * called, without verifying what the getter returns.
  38. * </p>
  39. *
  40. * @author Vaadin Ltd.
  41. * @version
  42. * @VERSION@
  43. * @since 3.0
  44. */
  45. @SuppressWarnings("serial")
  46. public class MethodProperty<T> extends AbstractProperty {
  47. private static final Logger logger = Logger.getLogger(MethodProperty.class
  48. .getName());
  49. /**
  50. * The object that includes the property the MethodProperty is bound to.
  51. */
  52. private transient Object instance;
  53. /**
  54. * Argument arrays for the getter and setter methods.
  55. */
  56. private transient Object[] setArgs, getArgs;
  57. /**
  58. * The getter and setter methods.
  59. */
  60. private transient Method setMethod, getMethod;
  61. /**
  62. * Index of the new value in the argument list for the setter method. If the
  63. * setter method requires several parameters, this index tells which one is
  64. * the actual value to change.
  65. */
  66. private int setArgumentIndex;
  67. /**
  68. * Type of the property.
  69. */
  70. private transient Class<? extends T> type;
  71. /* Special serialization to handle method references */
  72. private void writeObject(java.io.ObjectOutputStream out) throws IOException {
  73. out.defaultWriteObject();
  74. SerializerHelper.writeClass(out, type);
  75. out.writeObject(instance);
  76. out.writeObject(setArgs);
  77. out.writeObject(getArgs);
  78. if (setMethod != null) {
  79. out.writeObject(setMethod.getName());
  80. SerializerHelper
  81. .writeClassArray(out, setMethod.getParameterTypes());
  82. } else {
  83. out.writeObject(null);
  84. out.writeObject(null);
  85. }
  86. if (getMethod != null) {
  87. out.writeObject(getMethod.getName());
  88. SerializerHelper
  89. .writeClassArray(out, getMethod.getParameterTypes());
  90. } else {
  91. out.writeObject(null);
  92. out.writeObject(null);
  93. }
  94. };
  95. /* Special serialization to handle method references */
  96. private void readObject(java.io.ObjectInputStream in) throws IOException,
  97. ClassNotFoundException {
  98. in.defaultReadObject();
  99. try {
  100. @SuppressWarnings("unchecked")
  101. // business assumption; type parameters not checked at runtime
  102. Class<T> class1 = (Class<T>) SerializerHelper.readClass(in);
  103. type = class1;
  104. instance = in.readObject();
  105. setArgs = (Object[]) in.readObject();
  106. getArgs = (Object[]) in.readObject();
  107. String name = (String) in.readObject();
  108. Class<?>[] paramTypes = SerializerHelper.readClassArray(in);
  109. if (name != null) {
  110. setMethod = instance.getClass().getMethod(name, paramTypes);
  111. } else {
  112. setMethod = null;
  113. }
  114. name = (String) in.readObject();
  115. paramTypes = SerializerHelper.readClassArray(in);
  116. if (name != null) {
  117. getMethod = instance.getClass().getMethod(name, paramTypes);
  118. } else {
  119. getMethod = null;
  120. }
  121. } catch (SecurityException e) {
  122. logger.log(Level.SEVERE, "Internal deserialization error", e);
  123. } catch (NoSuchMethodException e) {
  124. logger.log(Level.SEVERE, "Internal deserialization error", e);
  125. }
  126. };
  127. /**
  128. * <p>
  129. * Creates a new instance of <code>MethodProperty</code> from a named bean
  130. * property. This constructor takes an object and the name of a bean
  131. * property and initializes itself with the accessor methods for the
  132. * property.
  133. * </p>
  134. * <p>
  135. * The getter method of a <code>MethodProperty</code> instantiated with this
  136. * constructor will be called with no arguments, and the setter method with
  137. * only the new value as the sole argument.
  138. * </p>
  139. *
  140. * <p>
  141. * If the setter method is unavailable, the resulting
  142. * <code>MethodProperty</code> will be read-only, otherwise it will be
  143. * read-write.
  144. * </p>
  145. *
  146. * <p>
  147. * Method names are constructed from the bean property by adding
  148. * get/is/are/set prefix and capitalising the first character in the name of
  149. * the given bean property.
  150. * </p>
  151. *
  152. * @param instance
  153. * the object that includes the property.
  154. * @param beanPropertyName
  155. * the name of the property to bind to.
  156. */
  157. @SuppressWarnings("unchecked")
  158. public MethodProperty(Object instance, String beanPropertyName) {
  159. final Class beanClass = instance.getClass();
  160. // Assure that the first letter is upper cased (it is a common
  161. // mistake to write firstName, not FirstName).
  162. if (Character.isLowerCase(beanPropertyName.charAt(0))) {
  163. final char[] buf = beanPropertyName.toCharArray();
  164. buf[0] = Character.toUpperCase(buf[0]);
  165. beanPropertyName = new String(buf);
  166. }
  167. // Find the get method
  168. getMethod = null;
  169. try {
  170. getMethod = initGetterMethod(beanPropertyName, beanClass);
  171. } catch (final java.lang.NoSuchMethodException ignored) {
  172. throw new MethodException(this, "Bean property " + beanPropertyName
  173. + " can not be found");
  174. }
  175. // In case the get method is found, resolve the type
  176. Class<?> returnType = getMethod.getReturnType();
  177. // Finds the set method
  178. setMethod = null;
  179. try {
  180. setMethod = beanClass.getMethod("set" + beanPropertyName,
  181. new Class[] { returnType });
  182. } catch (final java.lang.NoSuchMethodException skipped) {
  183. }
  184. // Gets the return type from get method
  185. if (returnType.isPrimitive()) {
  186. type = (Class<T>) convertPrimitiveType(returnType);
  187. if (type.isPrimitive()) {
  188. throw new MethodException(this, "Bean property "
  189. + beanPropertyName
  190. + " getter return type must not be void");
  191. }
  192. } else {
  193. type = (Class<T>) returnType;
  194. }
  195. setArguments(new Object[] {}, new Object[] { null }, 0);
  196. this.instance = instance;
  197. }
  198. /**
  199. * <p>
  200. * Creates a new instance of <code>MethodProperty</code> from named getter
  201. * and setter methods. The getter method of a <code>MethodProperty</code>
  202. * instantiated with this constructor will be called with no arguments, and
  203. * the setter method with only the new value as the sole argument.
  204. * </p>
  205. *
  206. * <p>
  207. * If the setter method is <code>null</code>, the resulting
  208. * <code>MethodProperty</code> will be read-only, otherwise it will be
  209. * read-write.
  210. * </p>
  211. *
  212. * @param type
  213. * the type of the property.
  214. * @param instance
  215. * the object that includes the property.
  216. * @param getMethodName
  217. * the name of the getter method.
  218. * @param setMethodName
  219. * the name of the setter method.
  220. *
  221. */
  222. public MethodProperty(Class<? extends T> type, Object instance,
  223. String getMethodName, String setMethodName) {
  224. this(type, instance, getMethodName, setMethodName, new Object[] {},
  225. new Object[] { null }, 0);
  226. }
  227. /**
  228. * <p>
  229. * Creates a new instance of <code>MethodProperty</code> with the getter and
  230. * setter methods. The getter method of a <code>MethodProperty</code>
  231. * instantiated with this constructor will be called with no arguments, and
  232. * the setter method with only the new value as the sole argument.
  233. * </p>
  234. *
  235. * <p>
  236. * If the setter method is <code>null</code>, the resulting
  237. * <code>MethodProperty</code> will be read-only, otherwise it will be
  238. * read-write.
  239. * </p>
  240. *
  241. * @param type
  242. * the type of the property.
  243. * @param instance
  244. * the object that includes the property.
  245. * @param getMethod
  246. * the getter method.
  247. * @param setMethod
  248. * the setter method.
  249. */
  250. public MethodProperty(Class<? extends T> type, Object instance,
  251. Method getMethod, Method setMethod) {
  252. this(type, instance, getMethod, setMethod, new Object[] {},
  253. new Object[] { null }, 0);
  254. }
  255. /**
  256. * <p>
  257. * Creates a new instance of <code>MethodProperty</code> from named getter
  258. * and setter methods and argument lists. The getter method of a
  259. * <code>MethodProperty</code> instantiated with this constructor will be
  260. * called with the getArgs as arguments. The setArgs will be used as the
  261. * arguments for the setter method, though the argument indexed by the
  262. * setArgumentIndex will be replaced with the argument passed to the
  263. * {@link #setValue(Object newValue)} method.
  264. * </p>
  265. *
  266. * <p>
  267. * For example, if the <code>setArgs</code> contains <code>A</code>,
  268. * <code>B</code> and <code>C</code>, and <code>setArgumentIndex =
  269. * 1</code>, the call <code>methodProperty.setValue(X)</code> would result
  270. * in the setter method to be called with the parameter set of
  271. * <code>{A, X, C}</code>
  272. * </p>
  273. *
  274. * @param type
  275. * the type of the property.
  276. * @param instance
  277. * the object that includes the property.
  278. * @param getMethodName
  279. * the name of the getter method.
  280. * @param setMethodName
  281. * the name of the setter method.
  282. * @param getArgs
  283. * the fixed argument list to be passed to the getter method.
  284. * @param setArgs
  285. * the fixed argument list to be passed to the setter method.
  286. * @param setArgumentIndex
  287. * the index of the argument in <code>setArgs</code> to be
  288. * replaced with <code>newValue</code> when
  289. * {@link #setValue(Object newValue)} is called.
  290. */
  291. @SuppressWarnings("unchecked")
  292. public MethodProperty(Class<? extends T> type, Object instance,
  293. String getMethodName, String setMethodName, Object[] getArgs,
  294. Object[] setArgs, int setArgumentIndex) {
  295. // Check the setargs and setargs index
  296. if (setMethodName != null && setArgs == null) {
  297. throw new IndexOutOfBoundsException("The setArgs can not be null");
  298. }
  299. if (setMethodName != null
  300. && (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length)) {
  301. throw new IndexOutOfBoundsException(
  302. "The setArgumentIndex must be >= 0 and < setArgs.length");
  303. }
  304. // Set type
  305. this.type = type;
  306. // Find set and get -methods
  307. final Method[] m = instance.getClass().getMethods();
  308. // Finds get method
  309. boolean found = false;
  310. for (int i = 0; i < m.length; i++) {
  311. // Tests the name of the get Method
  312. if (!m[i].getName().equals(getMethodName)) {
  313. // name does not match, try next method
  314. continue;
  315. }
  316. // Tests return type
  317. if (!type.equals(m[i].getReturnType())) {
  318. continue;
  319. }
  320. // Tests the parameter types
  321. final Class[] c = m[i].getParameterTypes();
  322. if (c.length != getArgs.length) {
  323. // not the right amount of parameters, try next method
  324. continue;
  325. }
  326. int j = 0;
  327. while (j < c.length) {
  328. if (getArgs[j] != null
  329. && !c[j].isAssignableFrom(getArgs[j].getClass())) {
  330. // parameter type does not match, try next method
  331. break;
  332. }
  333. j++;
  334. }
  335. if (j == c.length) {
  336. // all paramteters matched
  337. if (found == true) {
  338. throw new MethodException(this,
  339. "Could not uniquely identify " + getMethodName
  340. + "-method");
  341. } else {
  342. found = true;
  343. getMethod = m[i];
  344. }
  345. }
  346. }
  347. if (found != true) {
  348. throw new MethodException(this, "Could not find " + getMethodName
  349. + "-method");
  350. }
  351. // Finds set method
  352. if (setMethodName != null) {
  353. // Finds setMethod
  354. found = false;
  355. for (int i = 0; i < m.length; i++) {
  356. // Checks name
  357. if (!m[i].getName().equals(setMethodName)) {
  358. // name does not match, try next method
  359. continue;
  360. }
  361. // Checks parameter compatibility
  362. final Class[] c = m[i].getParameterTypes();
  363. if (c.length != setArgs.length) {
  364. // not the right amount of parameters, try next method
  365. continue;
  366. }
  367. int j = 0;
  368. while (j < c.length) {
  369. if (setArgs[j] != null
  370. && !c[j].isAssignableFrom(setArgs[j].getClass())) {
  371. // parameter type does not match, try next method
  372. break;
  373. } else if (j == setArgumentIndex && !c[j].equals(type)) {
  374. // Property type is not the same as setArg type
  375. break;
  376. }
  377. j++;
  378. }
  379. if (j == c.length) {
  380. // all parameters match
  381. if (found == true) {
  382. throw new MethodException(this,
  383. "Could not identify unique " + setMethodName
  384. + "-method");
  385. } else {
  386. found = true;
  387. setMethod = m[i];
  388. }
  389. }
  390. }
  391. if (found != true) {
  392. throw new MethodException(this, "Could not identify "
  393. + setMethodName + "-method");
  394. }
  395. }
  396. // Gets the return type from get method
  397. this.type = (Class<T>) convertPrimitiveType(type);
  398. setArguments(getArgs, setArgs, setArgumentIndex);
  399. this.instance = instance;
  400. }
  401. /**
  402. * <p>
  403. * Creates a new instance of <code>MethodProperty</code> from the getter and
  404. * setter methods, and argument lists.
  405. * </p>
  406. * <p>
  407. * This constructor behaves exactly like
  408. * {@link #MethodProperty(Class type, Object instance, String getMethodName, String setMethodName, Object [] getArgs, Object [] setArgs, int setArgumentIndex)}
  409. * except that instead of names of the getter and setter methods this
  410. * constructor is given the actual methods themselves.
  411. * </p>
  412. *
  413. * @param type
  414. * the type of the property.
  415. * @param instance
  416. * the object that includes the property.
  417. * @param getMethod
  418. * the getter method.
  419. * @param setMethod
  420. * the setter method.
  421. * @param getArgs
  422. * the fixed argument list to be passed to the getter method.
  423. * @param setArgs
  424. * the fixed argument list to be passed to the setter method.
  425. * @param setArgumentIndex
  426. * the index of the argument in <code>setArgs</code> to be
  427. * replaced with <code>newValue</code> when
  428. * {@link #setValue(Object newValue)} is called.
  429. */
  430. @SuppressWarnings("unchecked")
  431. public MethodProperty(Class type, Object instance, Method getMethod,
  432. Method setMethod, Object[] getArgs, Object[] setArgs,
  433. int setArgumentIndex) {
  434. if (getMethod == null) {
  435. throw new MethodException(this,
  436. "Property GET-method cannot not be null: " + type);
  437. }
  438. if (setMethod != null) {
  439. if (setArgs == null) {
  440. throw new IndexOutOfBoundsException(
  441. "The setArgs can not be null");
  442. }
  443. if (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length) {
  444. throw new IndexOutOfBoundsException(
  445. "The setArgumentIndex must be >= 0 and < setArgs.length");
  446. }
  447. }
  448. // Gets the return type from get method
  449. type = convertPrimitiveType(type);
  450. this.getMethod = getMethod;
  451. this.setMethod = setMethod;
  452. setArguments(getArgs, setArgs, setArgumentIndex);
  453. this.instance = instance;
  454. this.type = type;
  455. }
  456. /**
  457. * Find a getter method for a property (getXyz(), isXyz() or areXyz()).
  458. *
  459. * @param propertyName
  460. * name of the property
  461. * @param beanClass
  462. * class in which to look for the getter methods
  463. * @return Method
  464. * @throws NoSuchMethodException
  465. * if no getter found
  466. */
  467. static Method initGetterMethod(String propertyName, final Class<?> beanClass)
  468. throws NoSuchMethodException {
  469. propertyName = propertyName.substring(0, 1).toUpperCase()
  470. + propertyName.substring(1);
  471. Method getMethod = null;
  472. try {
  473. getMethod = beanClass.getMethod("get" + propertyName,
  474. new Class[] {});
  475. } catch (final java.lang.NoSuchMethodException ignored) {
  476. try {
  477. getMethod = beanClass.getMethod("is" + propertyName,
  478. new Class[] {});
  479. } catch (final java.lang.NoSuchMethodException ignoredAsWell) {
  480. getMethod = beanClass.getMethod("are" + propertyName,
  481. new Class[] {});
  482. }
  483. }
  484. return getMethod;
  485. }
  486. static Class<?> convertPrimitiveType(Class<?> type) {
  487. // Gets the return type from get method
  488. if (type.isPrimitive()) {
  489. if (type.equals(Boolean.TYPE)) {
  490. type = Boolean.class;
  491. } else if (type.equals(Integer.TYPE)) {
  492. type = Integer.class;
  493. } else if (type.equals(Float.TYPE)) {
  494. type = Float.class;
  495. } else if (type.equals(Double.TYPE)) {
  496. type = Double.class;
  497. } else if (type.equals(Byte.TYPE)) {
  498. type = Byte.class;
  499. } else if (type.equals(Character.TYPE)) {
  500. type = Character.class;
  501. } else if (type.equals(Short.TYPE)) {
  502. type = Short.class;
  503. } else if (type.equals(Long.TYPE)) {
  504. type = Long.class;
  505. }
  506. }
  507. return type;
  508. }
  509. /**
  510. * Returns the type of the Property. The methods <code>getValue</code> and
  511. * <code>setValue</code> must be compatible with this type: one must be able
  512. * to safely cast the value returned from <code>getValue</code> to the given
  513. * type and pass any variable assignable to this type as an argument to
  514. * <code>setValue</code>.
  515. *
  516. * @return type of the Property
  517. */
  518. @SuppressWarnings("unchecked")
  519. public final Class getType() {
  520. return type;
  521. }
  522. /**
  523. * Tests if the object is in read-only mode. In read-only mode calls to
  524. * <code>setValue</code> will throw <code>ReadOnlyException</code> and will
  525. * not modify the value of the Property.
  526. *
  527. * @return <code>true</code> if the object is in read-only mode,
  528. * <code>false</code> if it's not
  529. */
  530. @Override
  531. public boolean isReadOnly() {
  532. return super.isReadOnly() || (setMethod == null);
  533. }
  534. /**
  535. * Gets the value stored in the Property. The value is resolved by calling
  536. * the specified getter method with the argument specified at instantiation.
  537. *
  538. * @return the value of the Property
  539. */
  540. public Object getValue() {
  541. try {
  542. return getMethod.invoke(instance, getArgs);
  543. } catch (final Throwable e) {
  544. throw new MethodException(this, e);
  545. }
  546. }
  547. /**
  548. * <p>
  549. * Sets the setter method and getter method argument lists.
  550. * </p>
  551. *
  552. * @param getArgs
  553. * the fixed argument list to be passed to the getter method.
  554. * @param setArgs
  555. * the fixed argument list to be passed to the setter method.
  556. * @param setArgumentIndex
  557. * the index of the argument in <code>setArgs</code> to be
  558. * replaced with <code>newValue</code> when
  559. * {@link #setValue(Object newValue)} is called.
  560. */
  561. public void setArguments(Object[] getArgs, Object[] setArgs,
  562. int setArgumentIndex) {
  563. this.getArgs = new Object[getArgs.length];
  564. for (int i = 0; i < getArgs.length; i++) {
  565. this.getArgs[i] = getArgs[i];
  566. }
  567. this.setArgs = new Object[setArgs.length];
  568. for (int i = 0; i < setArgs.length; i++) {
  569. this.setArgs[i] = setArgs[i];
  570. }
  571. this.setArgumentIndex = setArgumentIndex;
  572. }
  573. /**
  574. * Sets the value of the property. This method supports setting from
  575. * <code>String</code>s if either <code>String</code> is directly assignable
  576. * to property type, or the type class contains a string constructor.
  577. *
  578. * @param newValue
  579. * the New value of the property.
  580. * @throws <code>Property.ReadOnlyException</code> if the object is in
  581. * read-only mode.
  582. * @throws <code>Property.ConversionException</code> if
  583. * <code>newValue</code> can't be converted into the Property's
  584. * native type directly or through <code>String</code>.
  585. * @see #invokeSetMethod(Object)
  586. */
  587. @SuppressWarnings("unchecked")
  588. public void setValue(Object newValue) throws Property.ReadOnlyException,
  589. Property.ConversionException {
  590. // Checks the mode
  591. if (isReadOnly()) {
  592. throw new Property.ReadOnlyException();
  593. }
  594. Object value = convertValue(newValue, type);
  595. invokeSetMethod(value);
  596. fireValueChange();
  597. }
  598. /**
  599. * Convert a value to the given type, using a constructor of the type that
  600. * takes a single String parameter (toString() for the value) if necessary.
  601. *
  602. * @param value
  603. * to convert
  604. * @param type
  605. * type into which the value should be converted
  606. * @return converted value
  607. */
  608. static Object convertValue(Object value, Class<?> type) {
  609. if (null == value || type.isAssignableFrom(value.getClass())) {
  610. return value;
  611. }
  612. // convert using a string constructor
  613. try {
  614. // Gets the string constructor
  615. final Constructor constr = type
  616. .getConstructor(new Class[] { String.class });
  617. // Create a new object from the string
  618. return constr.newInstance(new Object[] { value.toString() });
  619. } catch (final java.lang.Exception e) {
  620. throw new Property.ConversionException(e);
  621. }
  622. }
  623. /**
  624. * Internal method to actually call the setter method of the wrapped
  625. * property.
  626. *
  627. * @param value
  628. */
  629. protected void invokeSetMethod(Object value) {
  630. try {
  631. // Construct a temporary argument array only if needed
  632. if (setArgs.length == 1) {
  633. setMethod.invoke(instance, new Object[] { value });
  634. } else {
  635. // Sets the value to argument array
  636. final Object[] args = new Object[setArgs.length];
  637. for (int i = 0; i < setArgs.length; i++) {
  638. args[i] = (i == setArgumentIndex) ? value : setArgs[i];
  639. }
  640. setMethod.invoke(instance, args);
  641. }
  642. } catch (final InvocationTargetException e) {
  643. final Throwable targetException = e.getTargetException();
  644. throw new MethodException(this, targetException);
  645. } catch (final Exception e) {
  646. throw new MethodException(this, e);
  647. }
  648. }
  649. /**
  650. * <code>Exception</code> object that signals that there were problems
  651. * calling or finding the specified getter or setter methods of the
  652. * property.
  653. *
  654. * @author Vaadin Ltd.
  655. * @version
  656. * @VERSION@
  657. * @since 3.0
  658. */
  659. @SuppressWarnings("rawtypes")
  660. // Exceptions cannot be parameterized, ever.
  661. public static class MethodException extends RuntimeException {
  662. /**
  663. * The method property from which the exception originates from
  664. */
  665. private final Property property;
  666. /**
  667. * Cause of the method exception
  668. */
  669. private Throwable cause;
  670. /**
  671. * Constructs a new <code>MethodException</code> with the specified
  672. * detail message.
  673. *
  674. * @param property
  675. * the property.
  676. * @param msg
  677. * the detail message.
  678. */
  679. public MethodException(Property property, String msg) {
  680. super(msg);
  681. this.property = property;
  682. }
  683. /**
  684. * Constructs a new <code>MethodException</code> from another exception.
  685. *
  686. * @param property
  687. * the property.
  688. * @param cause
  689. * the cause of the exception.
  690. */
  691. public MethodException(Property property, Throwable cause) {
  692. this.property = property;
  693. this.cause = cause;
  694. }
  695. /**
  696. * @see java.lang.Throwable#getCause()
  697. */
  698. @Override
  699. public Throwable getCause() {
  700. return cause;
  701. }
  702. /**
  703. * Gets the method property this exception originates from.
  704. *
  705. * @return MethodProperty or null if not a valid MethodProperty
  706. */
  707. public MethodProperty getMethodProperty() {
  708. return (property instanceof MethodProperty) ? (MethodProperty) property
  709. : null;
  710. }
  711. /**
  712. * Gets the method property this exception originates from.
  713. *
  714. * @return Property from which the exception originates
  715. */
  716. public Property getProperty() {
  717. return property;
  718. }
  719. }
  720. /**
  721. * Sends a value change event to all registered listeners.
  722. *
  723. * Public for backwards compatibility, visibility may be reduced in future
  724. * versions.
  725. */
  726. @Override
  727. public void fireValueChange() {
  728. super.fireValueChange();
  729. }
  730. }