Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

MethodProperty.java 26KB

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