Coverage Report - org.jbehave.core.steps.ParameterConverters
 
Classes in this File Line Coverage Branch Coverage Complexity
ParameterConverters
100%
31/31
100%
8/8
2.254
ParameterConverters$BooleanConverter
100%
10/10
100%
2/2
2.254
ParameterConverters$BooleanListConverter
85%
17/20
62%
5/8
2.254
ParameterConverters$DateConverter
100%
12/12
75%
3/4
2.254
ParameterConverters$EnumConverter
100%
11/11
100%
2/2
2.254
ParameterConverters$EnumListConverter
94%
18/19
62%
5/8
2.254
ParameterConverters$ExamplesTableConverter
100%
9/9
100%
2/2
2.254
ParameterConverters$MethodReturningConverter
100%
10/10
100%
2/2
2.254
ParameterConverters$NumberConverter
100%
37/37
100%
36/36
2.254
ParameterConverters$NumberListConverter
100%
19/19
100%
8/8
2.254
ParameterConverters$ParameterConverter
N/A
N/A
2.254
ParameterConverters$ParameterConvertionFailed
100%
4/4
N/A
2.254
ParameterConverters$StringListConverter
100%
14/14
100%
8/8
2.254
 
 1  
 package org.jbehave.core.steps;
 2  
 
 3  
 import java.lang.reflect.Method;
 4  
 import java.lang.reflect.ParameterizedType;
 5  
 import java.lang.reflect.Type;
 6  
 import java.math.BigDecimal;
 7  
 import java.math.BigInteger;
 8  
 import java.text.DateFormat;
 9  
 import java.text.NumberFormat;
 10  
 import java.text.ParseException;
 11  
 import java.text.SimpleDateFormat;
 12  
 import java.util.ArrayList;
 13  
 import java.util.Date;
 14  
 import java.util.List;
 15  
 import java.util.Locale;
 16  
 
 17  
 import org.apache.commons.lang.BooleanUtils;
 18  
 import org.jbehave.core.model.ExamplesTable;
 19  
 import org.jbehave.core.model.ExamplesTableFactory;
 20  
 
 21  
 import static java.util.Arrays.asList;
 22  
 
 23  
 /**
 24  
  * <p>
 25  
  * Facade responsible for converting parameter values to Java objects.
 26  
  * </p>
 27  
  * <p>
 28  
  * Several converters are provided out-of-the-box:
 29  
  * <ul>
 30  
  * <li>{@link ParameterConverters.NumberConverter NumberConverter}</li>
 31  
  * <li>{@link ParameterConverters.NumberListConverter NumberListConverter}</li>
 32  
  * <li>{@link ParameterConverters.StringListConverter StringListConverter}</li>
 33  
  * <li>{@link ParameterConverters.DateConverter DateConverter}</li>
 34  
  * <li>{@link ParameterConverters.ExamplesTableConverter ExamplesTableConverter}</li>
 35  
  * <li>{@link ParameterConverters.MethodReturningConverter MethodReturningConverter}</li>
 36  
  * </ul>
 37  
  * </p>
 38  
  */
 39  
 public class ParameterConverters {
 40  
 
 41  1
     static final Locale DEFAULT_NUMBER_FORMAT_LOCAL = Locale.ENGLISH;
 42  
     static final String DEFAULT_COMMA = ",";
 43  
     static final String DEFAULT_TRUE_VALUE = "true";
 44  
     static final String DEFAULT_FALSE_VALUE = "false";
 45  
         
 46  
     private static final String NEWLINES_PATTERN = "(\n)|(\r\n)";
 47  1
     private static final String SYSTEM_NEWLINE = System.getProperty("line.separator");
 48  
     
 49  
     private final StepMonitor monitor;
 50  792
     private final List<ParameterConverter> converters = new ArrayList<ParameterConverter>();
 51  
 
 52  
     /** 
 53  
      * Default Parameters use a SilentStepMonitor, has English as Locale and use "," as list separator. 
 54  
      */
 55  
     public ParameterConverters() {
 56  792
         this(new SilentStepMonitor());
 57  792
     }
 58  
 
 59  
     /** 
 60  
      * Default ParameterConverters have English as Locale and use "," as list separator. 
 61  
      */
 62  
     public ParameterConverters(StepMonitor monitor) {
 63  792
             this(monitor , DEFAULT_NUMBER_FORMAT_LOCAL, DEFAULT_COMMA);
 64  792
     }
 65  
 
 66  
     /** 
 67  
      * Creates an ParameterConvertors for a given Locale.  When selecting
 68  
      * a listSeparator, please make sure that this character doesn't have a special
 69  
      * meaning in your Locale (for instance "," is used as decimal separator in some Locale)
 70  
      * @param monitor Monitor reporting the conversions
 71  
      * @param locale The Locale to use when reading numbers
 72  
      * @param listSeparator The list separator 
 73  
      */
 74  792
     public ParameterConverters(StepMonitor monitor, Locale locale, String listSeparator) {
 75  792
         this.monitor = monitor;
 76  792
         this.addConverters(defaultConverters(locale, listSeparator));            
 77  792
     }
 78  
     
 79  
     protected ParameterConverter[] defaultConverters(Locale locale, String listSeparator) {
 80  792
         String escapedListSeparator = escapeRegexPunctuation(listSeparator);
 81  792
         ParameterConverter[] defaultConverters = {
 82  
             new BooleanConverter(),
 83  
             new NumberConverter(NumberFormat.getInstance(locale)),
 84  
             new NumberListConverter(NumberFormat.getInstance(locale), escapedListSeparator), 
 85  
             new StringListConverter(escapedListSeparator),
 86  
             new DateConverter(), 
 87  
             new ExamplesTableConverter(new ExamplesTableFactory(this))
 88  
         };
 89  792
         return defaultConverters;
 90  
     }
 91  
 
 92  
     //TODO : This is a duplicate from RegExpPrefixCapturing
 93  
     private String escapeRegexPunctuation(String matchThis) {
 94  792
         return matchThis.replaceAll("([\\[\\]\\{\\}\\?\\^\\.\\*\\(\\)\\+\\\\])", "\\\\$1");
 95  
     }
 96  
 
 97  
     
 98  
     public ParameterConverters addConverters(ParameterConverter... converters) {
 99  794
         return addConverters(asList(converters));
 100  
     }
 101  
 
 102  
     public ParameterConverters addConverters(List<ParameterConverter> converters) {
 103  816
         this.converters.addAll(0, converters);
 104  816
         return this;
 105  
     }
 106  
 
 107  
     public Object convert(String value, Type type) {
 108  
 
 109  
         // check if any converters accepts type
 110  69
         for (ParameterConverter converter : converters) {
 111  314
             if (converter.accept(type)) {
 112  27
                 Object converted = converter.convertValue(value, type);
 113  27
                 monitor.convertedValueOfType(value, type, converted, converter.getClass());
 114  27
                 return converted;
 115  
             }
 116  
         }
 117  
 
 118  42
         if (type == String.class) {
 119  41
             return replaceNewlinesWithSystemNewlines(value);
 120  
         }
 121  
 
 122  1
         throw new ParameterConvertionFailed("No parameter converter for " + type);
 123  
     }
 124  
 
 125  
     private Object replaceNewlinesWithSystemNewlines(String value) {
 126  41
         return value.replaceAll(NEWLINES_PATTERN, SYSTEM_NEWLINE);
 127  
     }
 128  
 
 129  
     public static interface ParameterConverter {
 130  
 
 131  
         boolean accept(Type type);
 132  
 
 133  
         Object convertValue(String value, Type type);
 134  
 
 135  
     }
 136  
 
 137  
     @SuppressWarnings("serial")
 138  
     public static class ParameterConvertionFailed extends RuntimeException {
 139  
 
 140  
         public ParameterConvertionFailed(String message) {
 141  1
             super(message);
 142  1
         }
 143  
 
 144  
         public ParameterConvertionFailed(String message, Throwable cause) {
 145  5
             super(message, cause);
 146  5
         }
 147  
     }
 148  
 
 149  
     /**
 150  
      * <p>
 151  
      * Converts values to numbers, supporting any subclass of {@link Number}
 152  
      * (including generic Number type), and it unboxed counterpart, using a
 153  
      * {@link NumberFormat} to parse to a {@link Number} and to convert it to a
 154  
      * specific number type:
 155  
      * <ul>
 156  
      * <li>Byte, byte: {@link Number#byteValue()}</li>
 157  
      * <li>Short, short: {@link Number#shortValue()}</li>
 158  
      * <li>Integer, int: {@link Number#intValue()}</li>
 159  
      * <li>Float, float: {@link Number#floatValue()}</li>
 160  
      * <li>Long, long: {@link Number#longValue()}</li>
 161  
      * <li>Double, double: {@link Number#doubleValue()}</li>
 162  
      * <li>BigInteger: {@link BigInteger#valueOf(Long)}</li>
 163  
      * <li>BigDecimal: {@link BigDecimal#valueOf(Double)}</li></li>
 164  
      * </ul>
 165  
      * If no number format is provided, it defaults to
 166  
      * {@link NumberFormat#getInstance(Locale.ENGLISH)}.
 167  
      * <p>
 168  
      * The localized instance {@link NumberFormat#getInstance(Locale)} can be
 169  
      * used to convert numbers in specific locales.
 170  
      * </p>
 171  
      */
 172  
     public static class NumberConverter implements ParameterConverter {
 173  
 
 174  1
         private static List<Class<?>> primitiveTypes = asList(new Class<?>[] { byte.class, short.class, int.class,
 175  
                 float.class, long.class, double.class });
 176  
 
 177  
         private final NumberFormat numberFormat;
 178  
 
 179  
         public NumberConverter() {
 180  3
             this(NumberFormat.getInstance(DEFAULT_NUMBER_FORMAT_LOCAL));
 181  3
         }
 182  
 
 183  1593
         public NumberConverter(NumberFormat numberFormat) {
 184  1593
             this.numberFormat = numberFormat;
 185  1593
         }
 186  
 
 187  
         public boolean accept(Type type) {
 188  109
             if (type instanceof Class<?>) {
 189  104
                 return Number.class.isAssignableFrom((Class<?>) type) || primitiveTypes.contains(type);
 190  
             }
 191  5
             return false;
 192  
         }
 193  
 
 194  
         public Object convertValue(String value, Type type) {
 195  
             try {
 196  122
                 Number n = numberFormat.parse(value);
 197  120
                 if (type == Byte.class || type == byte.class) {
 198  6
                     return n.byteValue();
 199  114
                 } else if (type == Short.class || type == short.class) {
 200  6
                     return n.shortValue();
 201  108
                 } else if (type == Integer.class || type == int.class) {
 202  23
                     return n.intValue();
 203  85
                 } else if (type == Float.class || type == float.class) {
 204  21
                     return n.floatValue();
 205  64
                 } else if (type == Long.class || type == long.class) {
 206  15
                     return n.longValue();
 207  49
                 } else if (type == Double.class || type == double.class) {
 208  22
                     return n.doubleValue();
 209  27
                 } else if (type == BigInteger.class) {
 210  3
                     return BigInteger.valueOf(n.longValue());
 211  24
                 } else if (type == BigDecimal.class) {
 212  12
                     return new BigDecimal(canonicalize(value));
 213  
                 } else {
 214  12
                     return n;
 215  
                 }
 216  2
             } catch (ParseException e) {
 217  2
                 throw new ParameterConvertionFailed(value, e);
 218  
             }
 219  
         }
 220  
 
 221  
         private String canonicalize(String value) {
 222  12
             char decimalPointSeparator = numberFormat.format(1.01).charAt(1);
 223  12
             int decimalPointPosition = value.lastIndexOf(decimalPointSeparator);
 224  12
             value = value.trim();
 225  12
             if (decimalPointPosition != -1) {
 226  9
                 String sf = value.substring(0, decimalPointPosition).replace("[^0-9]", "");
 227  9
                 String dp = value.substring(decimalPointPosition+1);
 228  9
                 return sf + "." + dp;
 229  
             }
 230  3
             return value.replace(' ', ',');
 231  
         }
 232  
 
 233  
     }
 234  
 
 235  
     /**
 236  
      * Converts value to list of numbers. Splits value to a list, using an
 237  
      * injectable value separator (defaulting to ",") and converts each element
 238  
      * of list via the {@link NumberConverter}, using the {@link NumberFormat}
 239  
      * provided (defaulting to {@link NumberFormat#getInstance(Locale.ENGLISH)}).
 240  
      */
 241  
     public static class NumberListConverter implements ParameterConverter {
 242  
 
 243  
         private final NumberConverter numberConverter;
 244  
         private final String valueSeparator;
 245  
 
 246  
         public NumberListConverter() {
 247  2
             this(NumberFormat.getInstance(DEFAULT_NUMBER_FORMAT_LOCAL), DEFAULT_COMMA);
 248  2
         }
 249  
 
 250  
         /**
 251  
          * @param numberFormat Specific NumberFormat to use.
 252  
          * @param valueSeparator A regexp to use as list separate
 253  
          */
 254  796
         public NumberListConverter(NumberFormat numberFormat, String valueSeparator) {
 255  796
             this.numberConverter = new NumberConverter(numberFormat);
 256  796
             this.valueSeparator = valueSeparator;
 257  796
         }
 258  
 
 259  
         public boolean accept(Type type) {
 260  49
             if (type instanceof ParameterizedType) {
 261  7
                 Type rawType = rawType(type);
 262  7
                 Type argumentType = argumentType(type);
 263  7
                 return List.class.isAssignableFrom((Class<?>) rawType)
 264  
                         && Number.class.isAssignableFrom((Class<?>) argumentType);
 265  
             }
 266  42
             return false;
 267  
         }
 268  
 
 269  
         private Type rawType(Type type) {
 270  7
             return ((ParameterizedType) type).getRawType();
 271  
         }
 272  
 
 273  
         private Type argumentType(Type type) {
 274  18
             return ((ParameterizedType) type).getActualTypeArguments()[0];
 275  
         }
 276  
 
 277  
         @SuppressWarnings("unchecked")
 278  
         public Object convertValue(String value, Type type) {
 279  11
             Class<? extends Number> argumentType = (Class<? extends Number>) argumentType(type);
 280  11
             List<String> values = trim(asList(value.split(valueSeparator)));
 281  11
             List<Number> numbers = new ArrayList<Number>();
 282  11
             for (String numberValue : values) {
 283  40
                 numbers.add((Number) numberConverter.convertValue(numberValue, argumentType));
 284  
             }
 285  10
             return numbers;
 286  
         }
 287  
 
 288  
     }
 289  
 
 290  
     /**
 291  
      * Converts value to list of String. Splits value to a list, using an
 292  
      * injectable value separator (defaults to ",") and trimming each element of
 293  
      * the list.
 294  
      */
 295  
     public static class StringListConverter implements ParameterConverter {
 296  
 
 297  
         private String valueSeparator;
 298  
 
 299  
         public StringListConverter() {
 300  1
             this(DEFAULT_COMMA);
 301  1
         }
 302  
 
 303  
         /**
 304  
          * @param numberFormat Specific NumberFormat to use.
 305  
          * @param valueSeparator A regexp to use as list separate
 306  
          */
 307  793
         public StringListConverter(String valueSeparator) {
 308  793
             this.valueSeparator = valueSeparator;
 309  793
         }
 310  
 
 311  
         public boolean accept(Type type) {
 312  46
             if (type instanceof ParameterizedType) {
 313  4
                 ParameterizedType parameterizedType = (ParameterizedType) type;
 314  4
                 Type rawType = parameterizedType.getRawType();
 315  4
                 Type argumentType = parameterizedType.getActualTypeArguments()[0];
 316  4
                 return List.class.isAssignableFrom((Class<?>) rawType)
 317  
                         && String.class.isAssignableFrom((Class<?>) argumentType);
 318  
             }
 319  42
             return false;
 320  
         }
 321  
 
 322  
         public Object convertValue(String value, Type type) {
 323  3
             if (value.trim().length() == 0)
 324  1
                 return asList();
 325  2
             return trim(asList(value.split(valueSeparator)));
 326  
         }
 327  
 
 328  
     }
 329  
 
 330  
     public static List<String> trim(List<String> values) {
 331  15
         List<String> trimmed = new ArrayList<String>();
 332  15
         for (String value : values) {
 333  51
             trimmed.add(value.trim());
 334  
         }
 335  15
         return trimmed;
 336  
     }
 337  
 
 338  
     /**
 339  
      * Parses value to a {@link Date} using an injectable {@link DateFormat}
 340  
      * (defaults to <b>new SimpleDateFormat("dd/MM/yyyy")</b>)
 341  
      */
 342  
     public static class DateConverter implements ParameterConverter {
 343  
 
 344  1
         public static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("dd/MM/yyyy");
 345  
 
 346  
         private final DateFormat dateFormat;
 347  
 
 348  
         public DateConverter() {
 349  794
             this(DEFAULT_FORMAT);
 350  794
         }
 351  
 
 352  795
         public DateConverter(DateFormat dateFormat) {
 353  795
             this.dateFormat = dateFormat;
 354  795
         }
 355  
 
 356  
         public boolean accept(Type type) {
 357  48
             if (type instanceof Class<?>) {
 358  46
                 return Date.class.isAssignableFrom((Class<?>) type);
 359  
             }
 360  2
             return false;
 361  
         }
 362  
 
 363  
         public Object convertValue(String value, Type type) {
 364  
             try {
 365  3
                 return dateFormat.parse(value);
 366  1
             } catch (ParseException e) {
 367  1
                 throw new ParameterConvertionFailed("Failed to convert value " + value + " with date format "
 368  
                         + (dateFormat instanceof SimpleDateFormat ? ((SimpleDateFormat) dateFormat).toPattern() : dateFormat), e);
 369  
             }
 370  
         }
 371  
 
 372  
     }
 373  
 
 374  
     public static class BooleanConverter implements ParameterConverter {
 375  
         private String trueValue;
 376  
         private String falseValue;
 377  
 
 378  
         public BooleanConverter() {
 379  793
             this(DEFAULT_TRUE_VALUE, DEFAULT_FALSE_VALUE);
 380  793
         }
 381  
 
 382  794
         public BooleanConverter(String trueValue, String falseValue) {
 383  794
             this.trueValue = trueValue;
 384  794
             this.falseValue = falseValue;
 385  794
         }
 386  
 
 387  
         public boolean accept(Type type) {
 388  69
             if (type instanceof Class<?>) {
 389  63
                 return Boolean.class.isAssignableFrom((Class<?>) type);
 390  
             }
 391  6
             return false;
 392  
         }
 393  
 
 394  
         public Object convertValue(String value, Type type) {
 395  9
             return BooleanUtils.toBoolean(value, trueValue, falseValue);
 396  
         }
 397  
     }
 398  
 
 399  
     public static class BooleanListConverter implements ParameterConverter {
 400  
         private final BooleanConverter booleanConverter;
 401  
         private String valueSeparator;
 402  
 
 403  
         public BooleanListConverter() {
 404  1
             this(DEFAULT_COMMA, DEFAULT_TRUE_VALUE, DEFAULT_FALSE_VALUE);
 405  1
         }
 406  
 
 407  
         public BooleanListConverter(String valueSeparator) {
 408  0
             this(valueSeparator, DEFAULT_TRUE_VALUE, DEFAULT_FALSE_VALUE);
 409  0
         }
 410  
 
 411  1
         public BooleanListConverter(String valueSeparator, String trueValue, String falseValue) {
 412  1
             this.valueSeparator = valueSeparator;
 413  1
             booleanConverter = new BooleanConverter(trueValue, falseValue);
 414  1
         }
 415  
 
 416  
         public boolean accept(Type type) {
 417  1
             if (type instanceof ParameterizedType) {
 418  1
                 Type rawType = rawType(type);
 419  1
                 Type argumentType = argumentType(type);
 420  1
                 return List.class.isAssignableFrom((Class<?>) rawType)
 421  
                         && Boolean.class.isAssignableFrom((Class<?>) argumentType);
 422  
             }
 423  0
             return false;
 424  
         }
 425  
 
 426  
         public Object convertValue(String value, Type type) {
 427  1
             List<String> values = trim(asList(value.split(valueSeparator)));
 428  1
             List<Boolean> booleans = new ArrayList<Boolean>();
 429  
 
 430  1
             for (String booleanValue : values) {
 431  3
                 booleans.add((Boolean) booleanConverter.convertValue(booleanValue, type));
 432  
             }
 433  1
             return booleans;
 434  
         }
 435  
 
 436  
         private Type rawType(Type type) {
 437  1
             return ((ParameterizedType) type).getRawType();
 438  
         }
 439  
 
 440  
         private Type argumentType(Type type) {
 441  1
             return ((ParameterizedType) type).getActualTypeArguments()[0];
 442  
         }
 443  
     }
 444  
 
 445  
     /**
 446  
      * Parses value to any {@link Enum}
 447  
      */
 448  3
     public static class EnumConverter implements ParameterConverter {
 449  
 
 450  
         public boolean accept(Type type) {
 451  4
             if (type instanceof Class<?>) {
 452  3
                 return ((Class<?>) type).isEnum();
 453  
             }
 454  1
             return false;
 455  
         }
 456  
 
 457  
         public Object convertValue(String value, Type type) {
 458  5
             String typeClass = ((Class<?>) type).getName();
 459  5
             Class<?> enumClass = (Class<?>) type;
 460  5
             Method valueOfMethod = null;
 461  
             try {
 462  5
                 valueOfMethod = enumClass.getMethod("valueOf", new Class[] { String.class });
 463  5
                 return valueOfMethod.invoke(enumClass, new Object[] { value });
 464  1
             } catch (Exception e) {
 465  1
                 throw new ParameterConvertionFailed("Failed to convert " + value + " for Enum " + typeClass, e);
 466  
             }
 467  
         }
 468  
     }
 469  
  
 470  
     /**
 471  
      * Parses value to list of the same {@link Enum}, using an injectable
 472  
      * value separator (defaults to ",") and trimming each element of the
 473  
      * list.
 474  
      */
 475  
     public static class EnumListConverter implements ParameterConverter {
 476  
         private final EnumConverter enumConverter;
 477  
         private String valueSeparator;
 478  
 
 479  
         public EnumListConverter() {
 480  1
             this(DEFAULT_COMMA);
 481  1
         }
 482  
         
 483  1
         public EnumListConverter(String valueSeparator) {
 484  1
             this.enumConverter = new EnumConverter();
 485  1
             this.valueSeparator = valueSeparator;
 486  1
         }
 487  
 
 488  
         public boolean accept(Type type) {
 489  1
             if (type instanceof ParameterizedType) {
 490  1
                 Type rawType = rawType(type);
 491  1
                 Type argumentType = argumentType(type);
 492  1
                 return List.class.isAssignableFrom((Class<?>) rawType)
 493  
                         && enumConverter.accept(argumentType);
 494  
             }
 495  0
             return false;
 496  
         }
 497  
 
 498  
         public Object convertValue(String value, Type type) {
 499  1
             Type argumentType = argumentType(type);
 500  1
             List<String> values = trim(asList(value.split(valueSeparator)));
 501  1
             List<Enum<?>> enums = new ArrayList<Enum<?>>();
 502  1
             for (String string : values) {
 503  3
                 enums.add((Enum<?>) enumConverter.convertValue(string, argumentType));
 504  
             }
 505  1
             return enums;
 506  
         }
 507  
 
 508  
         private Type rawType(Type type) {
 509  1
             return ((ParameterizedType) type).getRawType();
 510  
         }
 511  
 
 512  
         private Type argumentType(Type type) {
 513  2
             return ((ParameterizedType) type).getActualTypeArguments()[0];
 514  
         }
 515  
     }
 516  
     
 517  
     /**
 518  
      * Converts value to {@link ExamplesTable} using a {@link ExamplesTableFactory}.
 519  
      */
 520  
     public static class ExamplesTableConverter implements ParameterConverter {
 521  
 
 522  
         private final ExamplesTableFactory factory;
 523  
         
 524  
         public ExamplesTableConverter(){
 525  1
             this(new ExamplesTableFactory());           
 526  1
         }
 527  
 
 528  793
         public ExamplesTableConverter(ExamplesTableFactory factory){
 529  793
             this.factory = factory;            
 530  793
         }
 531  
 
 532  
         public boolean accept(Type type) {
 533  45
             if (type instanceof Class<?>) {
 534  44
                 return ExamplesTable.class.isAssignableFrom((Class<?>) type);
 535  
             }
 536  1
             return false;
 537  
         }
 538  
 
 539  
         public Object convertValue(String value, Type type) {
 540  1
             return factory.createExamplesTable(value);
 541  
         }
 542  
 
 543  
     }
 544  
 
 545  
     /**
 546  
      * Invokes method on instance to return value.
 547  
      */
 548  
     public static class MethodReturningConverter implements ParameterConverter {
 549  
         private Object instance;
 550  
         private Method method;
 551  
 
 552  5
         public MethodReturningConverter(Method method, Object instance) {
 553  5
             this.method = method;
 554  5
             this.instance = instance;
 555  5
         }
 556  
 
 557  
         public boolean accept(Type type) {
 558  16
             if (type instanceof Class<?>) {
 559  15
                 return method.getReturnType().isAssignableFrom((Class<?>) type);
 560  
             }
 561  1
             return false;
 562  
         }
 563  
 
 564  
         public Object convertValue(String value, Type type) {
 565  
             try {
 566  5
                 return method.invoke(instance, value);
 567  1
             } catch (Exception e) {
 568  1
                 throw new ParameterConvertionFailed("Failed to invoke method " + method + " with value " + value
 569  
                         + " in " + instance, e);
 570  
             }
 571  
         }
 572  
 
 573  
     }
 574  
 }