001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.app.config; 017 018 019import java.io.File; 020import java.lang.reflect.*; 021import java.util.*; 022import java.util.concurrent.ConcurrentHashMap; 023 024public class JbootConfigKit { 025 026 027 public static <T> T newInstance(Class<T> clazz) { 028 try { 029 Constructor<T> constructor = clazz.getDeclaredConstructor(); 030 constructor.setAccessible(true); 031 return constructor.newInstance(); 032 } catch (Exception e) { 033 e.printStackTrace(); 034 } 035 return null; 036 } 037 038 public static List<ConfigPara> parseParas(String string) { 039 if (isBlank(string)) { 040 return null; 041 } 042 043 List<ConfigPara> paras = null; 044 ConfigPara para = null; 045 int index = 0; 046 boolean hasDefaultValue = false; 047 char[] chars = string.toCharArray(); 048 for (char c : chars) { 049 //第一个字符是 '{' 会出现 ArrayIndexOutOfBoundsException 错误 050 if (c == '{' && index > 0 && chars[index - 1] == '$' && para == null) { 051 para = new ConfigPara(); 052 hasDefaultValue = false; 053 para.setStart(index - 1); 054 } else if (c == '}' && para != null) { 055 para.setEnd(index); 056 if (paras == null) { 057 paras = new LinkedList<>(); 058 } 059 paras.add(para); 060 para = null; 061 } else if (para != null) { 062 if (c == ':' && !hasDefaultValue) { 063 hasDefaultValue = true; 064 } else if (hasDefaultValue) { 065 para.appendToDefaultValue(c); 066 } else { 067 para.appendToKey(c); 068 } 069 } 070 index++; 071 } 072 return paras; 073 } 074 075 076 public static String parseValue(String value) { 077 return parseValue(JbootConfigManager.me(), value); 078 } 079 080 public static String parseValue(JbootConfigManager manager, String value) { 081 List<ConfigPara> paras = parseParas(value); 082 if (paras == null || paras.size() == 0) { 083 return value; 084 } 085 StringBuilder retBuilder = new StringBuilder(value.length()); 086 int index = 0; 087 for (ConfigPara para : paras) { 088 if (para.getStart() > index) { 089 retBuilder.append(value, index, para.getStart()); 090 } 091 092 String configValue = manager.getConfigValue(para.getKey()); 093 configValue = isNotBlank(configValue) ? configValue : para.getDefaultValue(); 094 retBuilder.append(configValue); 095 index = para.getEnd() + 1; 096 } 097 098 if (index < value.length()) { 099 retBuilder.append(value, index, value.length()); 100 } 101 102 return retBuilder.toString(); 103 } 104 105 106 public static List<Method> getClassSetMethods(Class<?> clazz) { 107 List<Method> setMethods = new ArrayList<>(); 108 Method[] methods = clazz.getMethods(); 109 for (Method method : methods) { 110 if (method.getName().startsWith("set") 111 && method.getName().length() > 3 112 && Character.isUpperCase(method.getName().charAt(3)) 113 && method.getParameterCount() == 1 114 && Modifier.isPublic(method.getModifiers()) 115 && !Modifier.isStatic(method.getModifiers())) { 116 117 setMethods.add(method); 118 } 119 } 120 return setMethods; 121 } 122 123 public static String firstCharToLowerCase(String str) { 124 char firstChar = str.charAt(0); 125 if (firstChar >= 'A' && firstChar <= 'Z') { 126 char[] arr = str.toCharArray(); 127 arr[0] += ('a' - 'A'); 128 return new String(arr); 129 } 130 return str; 131 } 132 133 public static boolean isBlank(String str) { 134 if (str == null) { 135 return true; 136 } 137 138 for (int i = 0, len = str.length(); i < len; i++) { 139 if (str.charAt(i) > ' ') { 140 return false; 141 } 142 } 143 return true; 144 } 145 146 public static boolean isNotBlank(Object str) { 147 return str != null && !isBlank(str.toString()); 148 } 149 150 public static boolean areNotBlank(String... strs) { 151 if (strs == null || strs.length == 0) { 152 return false; 153 } 154 155 for (String string : strs) { 156 if (isBlank(string)) { 157 return false; 158 } 159 } 160 return true; 161 } 162 163 164 static Properties readProperties(String fileName) { 165 return readProperties(null,fileName); 166 } 167 168 static Properties readProperties(String path, String fileName) { 169 fileName = appendSuffixIfNecessary(fileName); 170 if (path != null && path.trim().length() > 0) { 171 return new JbootProp(new File(path, fileName)).getProperties(); 172 } else { 173 return new JbootProp(fileName).getProperties(); 174 } 175 } 176 177 178 static Properties readExternalProperties(String fileName) { 179 fileName = appendSuffixIfNecessary(fileName); 180 String jarPath = JbootConfigKit.class.getProtectionDomain().getCodeSource().getLocation().getFile(); 181 File parentPath = new File(jarPath).getParentFile(); 182 File externalProperties = new File(parentPath, fileName); 183 return readPropertiesFile(externalProperties); 184 } 185 186 187 private static String appendSuffixIfNecessary(String fileName) { 188 fileName = fileName.trim(); 189 return fileName.toLowerCase().endsWith(".properties") ? fileName : fileName + ".properties"; 190 } 191 192 193 static Properties readPropertiesFile(File propFile) { 194 if (propFile.exists()) { 195 return new JbootProp(propFile).getProperties(); 196 } 197 return new Properties(); 198 } 199 200 201 public static Object convert(Class<?> convertClass, String s, Type genericType) { 202 203 if (convertClass == String.class || s == null || convertClass == Object.class) { 204 return s; 205 } 206 207 if (convertClass == Integer.class || convertClass == int.class) { 208 return Integer.parseInt(s); 209 } else if (convertClass == Long.class || convertClass == long.class) { 210 return Long.parseLong(s); 211 } else if (convertClass == Double.class || convertClass == double.class) { 212 return Double.parseDouble(s); 213 } else if (convertClass == Float.class || convertClass == float.class) { 214 return Float.parseFloat(s); 215 } else if (convertClass == Boolean.class || convertClass == boolean.class) { 216 String value = s.toLowerCase(); 217 if ("1".equals(value) || "true".equals(value)) { 218 return Boolean.TRUE; 219 } else if ("0".equals(value) || "false".equals(value)) { 220 return Boolean.FALSE; 221 } else { 222 throw new RuntimeException("Can not parse to boolean type of value: " + s); 223 } 224 } else if (convertClass == java.math.BigDecimal.class) { 225 return new java.math.BigDecimal(s); 226 } else if (convertClass == java.math.BigInteger.class) { 227 return new java.math.BigInteger(s); 228 } else if (convertClass == byte[].class) { 229 return s.getBytes(); 230 } else if (Map.class.isAssignableFrom(convertClass)) { 231 if (!s.contains(":") || !genericClassCheck(genericType)) { 232 return null; 233 } else { 234 Map map = convertClass == ConcurrentHashMap.class ? new ConcurrentHashMap() : new HashMap(); 235 String[] strings = s.split(","); 236 for (String kv : strings) { 237 int indexOf = kv.indexOf(":"); 238 if (indexOf > 0 && indexOf < kv.trim().length() - 1) { 239 map.put(kv.substring(0, indexOf).trim(), kv.substring(indexOf + 1).trim()); 240 } 241 } 242 return map; 243 } 244 } else if (List.class.isAssignableFrom(convertClass)) { 245 if (genericClassCheck(genericType)) { 246 List list = LinkedList.class == convertClass ? new LinkedList() : new ArrayList(); 247 String[] strings = s.split(","); 248 for (String s1 : strings) { 249 if (s1.trim().length() > 0) { 250 list.add(s1.trim()); 251 } 252 } 253 return list; 254 } else { 255 return null; 256 } 257 } else if (Set.class.isAssignableFrom(convertClass)) { 258 if (genericClassCheck(genericType)) { 259 Set set = LinkedHashSet.class == convertClass ? new LinkedHashSet() : new HashSet(); 260 String[] strings = s.split(","); 261 for (String s1 : strings) { 262 if (s1.trim().length() > 0) { 263 set.add(s1.trim()); 264 } 265 } 266 return set; 267 } else { 268 return null; 269 } 270 } else if (convertClass.isArray() && convertClass.getComponentType() == String.class) { 271 List<String> list = new LinkedList(); 272 String[] strings = s.split(","); 273 if (strings.length > 0) { 274 for (String s1 : strings) { 275 if (s1 != null && s1.trim().length() != 0) { 276 list.add(s1.trim()); 277 } 278 } 279 } 280 return list.toArray(new String[0]); 281 } else if (Class.class == convertClass) { 282 try { 283 return Class.forName(s, false, Thread.currentThread().getContextClassLoader()); 284 } catch (ClassNotFoundException e) { 285 e.printStackTrace(); 286 } 287 } 288 289 throw new RuntimeException(convertClass.getName() + " can not be converted, please use other type in your config class!"); 290 291 } 292 293 /** 294 * 对泛型类型进行检测,只支持 String 类型的泛型,或者不是泛型才会支持 295 * 296 * @param type 297 * @return 298 */ 299 private static boolean genericClassCheck(Type type) { 300 if (type instanceof ParameterizedType) { 301 for (Type at : ((ParameterizedType) type).getActualTypeArguments()) { 302 if (String.class != at) { 303 return false; 304 } 305 } 306 } 307 return true; 308 } 309 310}