• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.caliper.util;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.primitives.Primitives;
21 
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.text.ParseException;
26 import java.util.List;
27 
28 public class Parsers {
29   public static final Parser<String> IDENTITY = new Parser<String>() {
30     @Override public String parse(CharSequence in) {
31       return in.toString();
32     }
33   };
34 
35   private static final List<String> CONVERSION_METHOD_NAMES =
36       ImmutableList.of("fromString", "decode", "valueOf");
37 
38   /**
39    * Parser that tries, in this order:
40    * <ul>
41    * <li>ResultType.fromString(String)
42    * <li>ResultType.decode(String)
43    * <li>ResultType.valueOf(String)
44    * <li>new ResultType(String)
45    * </ul>
46    */
conventionalParser(Class<T> resultType)47   public static <T> Parser<T> conventionalParser(Class<T> resultType)
48       throws NoSuchMethodException {
49     if (resultType == String.class) {
50       @SuppressWarnings("unchecked") // T == String
51       Parser<T> identity = (Parser<T>) IDENTITY;
52       return identity;
53     }
54 
55     final Class<T> wrappedResultType = Primitives.wrap(resultType);
56 
57     for (String methodName : CONVERSION_METHOD_NAMES) {
58       try {
59         final Method method = wrappedResultType.getDeclaredMethod(methodName, String.class);
60 
61         if (Util.isStatic(method) && wrappedResultType.isAssignableFrom(method.getReturnType())) {
62           method.setAccessible(true); // to permit inner enums, etc.
63           return new InvokingParser<T>() {
64             @Override protected T invoke(String input) throws Exception {
65               return wrappedResultType.cast(method.invoke(null, input));
66             }
67           };
68         }
69       } catch (Exception tryAgain) {
70       }
71     }
72 
73     final Constructor<T> constr = wrappedResultType.getDeclaredConstructor(String.class);
74     constr.setAccessible(true);
75     return new InvokingParser<T>() {
76       @Override protected T invoke(String input) throws Exception {
77         return wrappedResultType.cast(constr.newInstance(input));
78       }
79     };
80   }
81 
82   abstract static class InvokingParser<T> implements Parser<T> {
83     @Override public T parse(CharSequence input) throws ParseException {
84       try {
85         return invoke(input.toString());
86       } catch (InvocationTargetException e) {
87         Throwable cause = e.getCause();
88         String desc = firstNonNull(cause.getMessage(), cause.getClass().getSimpleName());
89         throw newParseException(desc, cause);
90       } catch (Exception e) {
91         throw newParseException("Unknown parsing problem", e);
92       }
93     }
94 
95     protected abstract T invoke(String input) throws Exception;
96   }
97 
98   public static ParseException newParseException(String message, Throwable cause) {
99     ParseException pe = newParseException(message);
100     pe.initCause(cause);
101     return pe;
102   }
103 
104   public static ParseException newParseException(String message) {
105     return new ParseException(message, 0);
106   }
107 
108   private static <T> T firstNonNull(T first, T second) {
109     return (first != null) ? first : second;
110   }
111 }
112