View Javadoc

1   /*
2    * This file is part of hyphenType. hyphenType is free software: you can
3    * redistribute it and/or modify it under the terms of the GNU General Public
4    * License as published by the Free Software Foundation, either version 3 of the
5    * License, or (at your option) any later version. hyphenType is distributed in
6    * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
8    * the GNU General Public License for more details. You should have received a
9    * copy of the GNU General Public License along with hyphenType. If not, see
10   * <http://www.gnu.org/licenses/>.
11   */
12  package org.hyphenType.util.soc;
13  
14  import java.lang.reflect.Array;
15  import java.lang.reflect.Constructor;
16  import java.lang.reflect.InvocationTargetException;
17  import java.util.StringTokenizer;
18  
19  import org.hyphenType.debug.HTLogger;
20  
21  /**
22   * Converts strings to objects and vice-versa.
23   * 
24   * @author Aurelio Akira M. Matsui
25   */
26  public final class StringObjectConversion {
27  
28      /**
29       * Turns it into a library class.
30       */
31      private StringObjectConversion() {
32      }
33  
34      /**
35       * Translates a string into an object. The algorithm used is as follows. If
36       * {@code clazz} is {@link String}, simply returns the string value
37       * received. If {@code clazz} is primitive or a wrapper for a primitive,
38       * returns the result of calling a {@code valueOf} method. If {@code clazz} is
39       * of a type {@link Class}, it searches for the class using
40       * {@link Class#forName(String)}. Finally, if {@code clazz} does not match
41       * any of those tests, tries to construct a new object, guessing that
42       * {@code clazz} has a constructor that receives only a {@link String}.
43       * 
44       * @param <T> The type to convert to.
45       * @param clazz The same as the type T.
46       * @param value The string value of the object.
47       * @return The object equivalent to the string.
48       * @throws StringParsingError If there is any reflection problem.
49       */
50      public static <T> T fromString(final Class<? extends T> clazz, final String value) throws StringParsingError {
51          return fromString(clazz, value, false, "[", "]", ",");
52      }
53  
54      /**
55       * Translates a string into an object. The algorithm used is as follows. If
56       * {@code clazz} is {@link String}, simply returns the string value
57       * received. If {@code clazz} is primitive or a wrapper for a primitive,
58       * returns the result of calling a {@code valueOf} method. If {@code clazz} is
59       * of a type {@link Class}, it searches for the class using
60       * {@link Class#forName(String)}. Finally, if {@code clazz} does not match
61       * any of those tests, tries to construct a new object, guessing that
62       * {@code clazz} has a constructor that receives only a {@link String}.
63       * 
64       * @param <T> The type to convert to.
65       * @param clazz The same as the type T.
66       * @param value The string value of the object.
67       * @param arrayForgiving Whether it will forgive the absence of square brackets.
68       * @return The object equivalent to the string.
69       * @throws StringParsingError If there is any reflection problem.
70       */
71      public static <T> T fromString(final Class<? extends T> clazz, final String value, final boolean arrayForgiving) throws StringParsingError {
72          return fromString(clazz, value, arrayForgiving, "[", "]", ",");
73      }
74  
75      /**
76       * Translates a string into an object. The algorithm used is as follows. If
77       * {@code clazz} is {@link String}, simply returns the string value
78       * received. If {@code clazz} is primitive or a wrapper for a primitive,
79       * returns the result of calling a {@code valueOf} method. If {@code clazz} is
80       * of a type {@link Class}, it searches for the class using
81       * {@link Class#forName(String)}. Finally, if {@code clazz} does not match
82       * any of those tests, tries to construct a new object, guessing that
83       * {@code clazz} has a constructor that receives only a {@link String}.
84       * 
85       * @param <T> The type to convert to.
86       * @param clazz The same as the type T.
87       * @param value The string value of the object.
88       * @param arrayForgiving Whether it will forgive the absence of square brackets.
89       * @return The object equivalent to the string.
90       * @throws StringParsingError If there is any reflection problem.
91       */
92      public static <T> T fromString(final Class<? extends T> clazz, final String value, final boolean arrayForgiving, final String separator) throws StringParsingError {
93          return fromString(clazz, value, arrayForgiving, "[", "]", separator);
94      }
95  
96      /**
97       * Translates a string into an object. The algorithm used is as follows. If
98       * {@code clazz} is {@link String}, simply returns the string value
99       * received. If {@code clazz} is primitive or a wrapper for a primitive,
100      * returns the result of calling a {@code valueOf} method. If {@code clazz} is
101      * of a type {@link Class}, it searches for the class using
102      * {@link Class#forName(String)}. Finally, if {@code clazz} does not match
103      * any of those tests, tries to construct a new object, guessing that
104      * {@code clazz} has a constructor that receives only a {@link String}.
105      * 
106      * @param <T> The type to convert to.
107      * @param clazz The same as the type T.
108      * @param value The string value of the object.
109      * @param arrayForgiving Whether it will forgive the absence of square brackets.
110      * @param arrayStart
111      * @param arrayEng
112      * @param arraySeparator
113      * @return
114      * @throws StringParsingError
115      */
116     @SuppressWarnings("unchecked")
117     public static <T> T fromString(final Class<? extends T> clazz, final String value, final boolean arrayForgiving, final String arrayStart, final String arrayEnd, final String arraySeparator) throws StringParsingError {
118 
119         try {
120             if (clazz.equals(String.class)) {
121                 return (T) value;
122             }
123             if (clazz.equals(boolean.class)) {
124                 return (T) Boolean.valueOf(value);
125             }
126             if (clazz.equals(Boolean.class)) {
127                 return (T) Boolean.valueOf(value);
128             }
129             if (clazz.equals(byte.class)) {
130                 return (T) Byte.valueOf(value);
131             }
132             if (clazz.equals(Byte.class)) {
133                 return (T) Byte.valueOf(value);
134             }
135             if (clazz.equals(char.class)) {
136                 return (T) Character.valueOf(value.charAt(0));
137             }
138             if (clazz.equals(Character.class)) {
139                 return (T) Character.valueOf(value.charAt(0));
140             }
141             if (clazz.equals(short.class)) {
142                 return (T) Short.valueOf(value);
143             }
144             if (clazz.equals(Short.class)) {
145                 return (T) Short.valueOf(value);
146             }
147             if (clazz.equals(int.class)) {
148                 return (T) Integer.valueOf(value);
149             }
150             if (clazz.equals(Integer.class)) {
151                 return (T) Integer.valueOf(value);
152             }
153             if (clazz.equals(long.class)) {
154                 return (T) Long.valueOf(value);
155             }
156             if (clazz.equals(Long.class)) {
157                 return (T) Long.valueOf(value);
158             }
159             if (clazz.equals(float.class)) {
160                 return (T) Float.valueOf(value);
161             }
162             if (clazz.equals(Float.class)) {
163                 return (T) Float.valueOf(value);
164             }
165             if (clazz.equals(double.class)) {
166                 return (T) Double.valueOf(value);
167             }
168             if (clazz.equals(Double.class)) {
169                 return (T) Double.valueOf(value);
170             }
171             if (clazz.equals(Class.class)) {
172                 return (T) Class.forName(value);
173             }
174             if (clazz.isEnum()) {
175                 return (T) Enum.valueOf((Class<Enum>) clazz, value);
176             }
177             if (clazz.isArray()) {
178                 String correctedValue;
179                 if (arrayForgiving) {
180                     correctedValue = value;
181                     if(!value.startsWith(arrayStart)) {
182                         correctedValue = arrayStart + value + arrayEnd;
183                     }
184                 } else {
185                     correctedValue = value;
186                     if (!(value.startsWith(arrayStart) && value.endsWith(arrayEnd))) {
187                         throw new StringParsingError("Invalid string representation of an array:\"" + value + "\". Valid patterns should be between square brackets.");
188                     }
189                 }
190                 StringTokenizer tokenizer = new StringTokenizer(correctedValue.substring(1, correctedValue.length()-1), arraySeparator);
191                 Object result = Array.newInstance(clazz.getComponentType(), tokenizer.countTokens());
192                 int i = 0;
193                 while(tokenizer.hasMoreTokens()) {
194                     Array.set(result, i, fromString(clazz.getComponentType(), tokenizer.nextToken().trim()));
195                     i++;
196                 }
197                 return (T) result;
198             }
199             Constructor constructor;
200             constructor = clazz.getConstructor(String.class);
201             return (T) constructor.newInstance(value);
202         } catch (SecurityException e) {
203             throw new StringParsingError("Cannot access the constructor " + clazz.getName() + "(String)");
204         } catch (NoSuchMethodException e) {
205             throw new StringParsingError("Constructor " + clazz.getName() + "(String) not found");
206         } catch (ClassNotFoundException e) {
207             HTLogger.log(e);
208             throw new StringParsingError("Cannot find class " + value);
209         } catch (IllegalArgumentException e) {
210             throw new StringParsingError("Could not instantiate using value: " + value, e);
211         } catch (InstantiationException e) {
212             throw new StringParsingError("Could not instantiate using value: " + value, e);
213         } catch (IllegalAccessException e) {
214             throw new StringParsingError("Could not instantiate using value: " + value, e);
215         } catch (InvocationTargetException e) {
216             throw new StringParsingError("Could not instantiate using value: " + value, e);
217         } catch (Throwable e) {
218             throw new StringParsingError("Problems while parsing the value " + value + " to the class " + clazz.getName(), e);
219         }
220     }
221     
222     /**
223      * Parses the object into a primitive.
224      * 
225      * @param clazz The primitive class.
226      * @param object The object that will be converted to a primitive.
227      * @return The equivalent primitive, or null if there is no equivalent.
228      */
229     @SuppressWarnings("unchecked")
230     public static Object toPrimitive(final Class clazz, final Object object) {
231         if (clazz.equals(boolean.class)) {
232             return ((Boolean) object).booleanValue();
233         }
234         if (clazz.equals(Boolean.class)) {
235             return ((Boolean) object).booleanValue();
236         }
237         if (clazz.equals(byte.class)) {
238             return ((Byte) object).byteValue();
239         }
240         if (clazz.equals(Byte.class)) {
241             return ((Byte) object).byteValue();
242         }
243         if (clazz.equals(char.class)) {
244             return ((Character) object).charValue();
245         }
246         if (clazz.equals(Character.class)) {
247             return ((Character) object).charValue();
248         }
249         if (clazz.equals(short.class)) {
250             return ((Short) object).shortValue();
251         }
252         if (clazz.equals(Short.class)) {
253             return ((Short) object).shortValue();
254         }
255         if (clazz.equals(int.class)) {
256             return ((Integer) object).intValue();
257         }
258         if (clazz.equals(Integer.class)) {
259             return ((Integer) object).intValue();
260         }
261         if (clazz.equals(long.class)) {
262             return ((Long) object).longValue();
263         }
264         if (clazz.equals(Long.class)) {
265             return ((Long) object).longValue();
266         }
267         if (clazz.equals(float.class)) {
268             return ((Float) object).floatValue();
269         }
270         if (clazz.equals(Float.class)) {
271             return ((Float) object).floatValue();
272         }
273         if (clazz.equals(double.class)) {
274             return ((Double) object).doubleValue();
275         }
276         if (clazz.equals(Double.class)) {
277             return ((Double) object).doubleValue();
278         }
279         return null;
280     }
281 }