1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.joran.util;
15  
16  import ch.qos.logback.core.CoreConstants;
17  import ch.qos.logback.core.spi.ContextAware;
18  
19  import java.lang.reflect.Method;
20  import java.lang.reflect.Modifier;
21  import java.nio.charset.Charset;
22  import java.nio.charset.UnsupportedCharsetException;
23  
24  import static ch.qos.logback.core.CoreConstants.NULL_STR;
25  
26  /**
27   * Utility class which can convert string into objects.
28   * 
29   * @author Ceki Gülcü
30   *
31   */
32  public class StringToObjectConverter  {
33  
34      private static final Class<?>[] STRING_CLASS_PARAMETER = new Class[] { String.class };
35  
36      static public boolean canBeBuiltFromSimpleString(Class<?> parameterClass) {
37          Package p = parameterClass.getPackage();
38          if (parameterClass.isPrimitive()) {
39              return true;
40          } else if (p != null && "java.lang".equals(p.getName())) {
41              return true;
42          } else if (followsTheValueOfConvention(parameterClass)) {
43              return true;
44          } else if (parameterClass.isEnum()) {
45              return true;
46          } else if (isOfTypeCharset(parameterClass)) {
47              return true;
48          }
49          return false;
50      }
51  
52      /**
53       * Convert <code>val</code> a String parameter to an object of a given type.
54       */
55      @SuppressWarnings("unchecked")
56      static public Object convertArg(ContextAware ca, String val, Class<?> type) {
57          if (val == null) {
58              return null;
59          }
60          String v = val.trim();
61          if (String.class.isAssignableFrom(type)) {
62              return v;
63          } else if (Integer.TYPE.isAssignableFrom(type)) {
64              return Integer.valueOf(v);
65          } else if (Long.TYPE.isAssignableFrom(type)) {
66              return Long.valueOf(v);
67          } else if (Float.TYPE.isAssignableFrom(type)) {
68              return Float.valueOf(v);
69          } else if (Double.TYPE.isAssignableFrom(type)) {
70              return Double.valueOf(v);
71          } else if (Boolean.TYPE.isAssignableFrom(type)) {
72              if ("true".equalsIgnoreCase(v)) {
73                  return Boolean.TRUE;
74              } else if ("false".equalsIgnoreCase(v)) {
75                  return Boolean.FALSE;
76              }
77          } else if (type.isEnum()) {
78              return convertToEnum(ca, v, (Class<? extends Enum<?>>) type);
79          } else if (StringToObjectConverter.followsTheValueOfConvention(type)) {
80              return convertByValueOfMethod(ca, type, v);
81          } else if (isOfTypeCharset(type)) {
82              return convertToCharset(ca, val);
83          }
84  
85          return null;
86      }
87  
88      static private boolean isOfTypeCharset(Class<?> type) {
89          return Charset.class.isAssignableFrom(type);
90      }
91  
92      static private Charset convertToCharset(ContextAware ca, String val) {
93  
94          if (NULL_STR.equalsIgnoreCase(val)) {
95              ca.addInfo("Converting the string \"null\" as Charset.defaultCharset()");
96              return Charset.defaultCharset();
97          }
98  
99          try {
100             return Charset.forName(val);
101         } catch (UnsupportedCharsetException e) {
102             ca.addError("Failed to get charset [" + val + "]", e);
103             return null;
104         }
105     }
106 
107     // returned value may be null and in most cases it is null.
108     static public Method getValueOfMethod(Class<?> type) {
109         try {
110             return type.getMethod(CoreConstants.VALUE_OF, STRING_CLASS_PARAMETER);
111         } catch (NoSuchMethodException e) {
112             return null;
113         } catch (SecurityException e) {
114             return null;
115         }
116     }
117 
118     static public boolean followsTheValueOfConvention(Class<?> parameterClass) {
119         Method valueOfMethod = getValueOfMethod(parameterClass);
120         if (valueOfMethod == null)
121             return false;
122 
123         int mod = valueOfMethod.getModifiers();
124         return Modifier.isStatic(mod);
125     }
126 
127     private static Object convertByValueOfMethod(ContextAware ca, Class<?> type, String val) {
128         try {
129             Method valueOfMethod = type.getMethod(CoreConstants.VALUE_OF, STRING_CLASS_PARAMETER);
130             return valueOfMethod.invoke(null, val);
131         } catch (Exception e) {
132             ca.addError("Failed to invoke " + CoreConstants.VALUE_OF + "{} method in class [" + type.getName()
133                     + "] with value [" + val + "]");
134             return null;
135         }
136     }
137 
138     @SuppressWarnings({ "unchecked", "rawtypes" })
139     private static Object convertToEnum(ContextAware ca, String val, Class<? extends Enum> enumType) {
140         return Enum.valueOf(enumType, val);
141     }
142 
143     boolean isBuildableFromSimpleString() {
144         return false;
145     }
146 }