You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MethodProperty.java 27KB

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