001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.joran.util;
015
016import ch.qos.logback.core.CoreConstants;
017import ch.qos.logback.core.spi.ContextAware;
018
019import java.lang.reflect.Method;
020import java.lang.reflect.Modifier;
021import java.nio.charset.Charset;
022import java.nio.charset.UnsupportedCharsetException;
023
024import static ch.qos.logback.core.CoreConstants.NULL_STR;
025
026/**
027 * Utility class which can convert string into objects.
028 * 
029 * @author Ceki Gülcü
030 *
031 */
032public class StringToObjectConverter  {
033
034    private static final Class<?>[] STRING_CLASS_PARAMETER = new Class[] { String.class };
035
036    static public boolean canBeBuiltFromSimpleString(Class<?> parameterClass) {
037        Package p = parameterClass.getPackage();
038        if (parameterClass.isPrimitive()) {
039            return true;
040        } else if (p != null && "java.lang".equals(p.getName())) {
041            return true;
042        } else if (followsTheValueOfConvention(parameterClass)) {
043            return true;
044        } else if (parameterClass.isEnum()) {
045            return true;
046        } else if (isOfTypeCharset(parameterClass)) {
047            return true;
048        }
049        return false;
050    }
051
052    /**
053     * Convert <code>val</code> a String parameter to an object of a given type.
054     */
055    @SuppressWarnings("unchecked")
056    static public Object convertArg(ContextAware ca, String val, Class<?> type) {
057        if (val == null) {
058            return null;
059        }
060        String v = val.trim();
061        if (String.class.isAssignableFrom(type)) {
062            return v;
063        } else if (Integer.TYPE.isAssignableFrom(type)) {
064            return Integer.valueOf(v);
065        } else if (Long.TYPE.isAssignableFrom(type)) {
066            return Long.valueOf(v);
067        } else if (Float.TYPE.isAssignableFrom(type)) {
068            return Float.valueOf(v);
069        } else if (Double.TYPE.isAssignableFrom(type)) {
070            return Double.valueOf(v);
071        } else if (Boolean.TYPE.isAssignableFrom(type)) {
072            if ("true".equalsIgnoreCase(v)) {
073                return Boolean.TRUE;
074            } else if ("false".equalsIgnoreCase(v)) {
075                return Boolean.FALSE;
076            }
077        } else if (type.isEnum()) {
078            return convertToEnum(ca, v, (Class<? extends Enum<?>>) type);
079        } else if (StringToObjectConverter.followsTheValueOfConvention(type)) {
080            return convertByValueOfMethod(ca, type, v);
081        } else if (isOfTypeCharset(type)) {
082            return convertToCharset(ca, val);
083        }
084
085        return null;
086    }
087
088    static private boolean isOfTypeCharset(Class<?> type) {
089        return Charset.class.isAssignableFrom(type);
090    }
091
092    static private Charset convertToCharset(ContextAware ca, String val) {
093
094        if (NULL_STR.equalsIgnoreCase(val)) {
095            ca.addInfo("Converting the string \"null\" as Charset.defaultCharset()");
096            return Charset.defaultCharset();
097        }
098
099        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}