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

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