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.components.rpc; 017 018import io.jboot.Jboot; 019import io.jboot.utils.AnnotationUtil; 020import io.jboot.utils.CollectionUtil; 021import io.jboot.utils.StrUtil; 022 023import java.lang.reflect.Field; 024import java.lang.reflect.Method; 025import java.lang.reflect.Modifier; 026import java.util.ArrayList; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030 031/** 032 * @author michael yang (fuhai999@gmail.com) 033 * @Date: 2020/3/20 034 */ 035public class RPCUtil { 036 037 /** 038 * 根据注解来设置对象内容,参考 dubbo 下的 AbstractConfig 039 * 参考 {{@org.apache.dubbo.config.AbstractConfig#appendAnnotation }} 040 * 041 * @param annotationClass 042 * @param annotation 043 * @param appendTo 044 */ 045 public static void appendAnnotation(Class<?> annotationClass, Object annotation, Object appendTo) { 046 Method[] methods = annotationClass.getMethods(); 047 for (Method method : methods) { 048 if (method.getDeclaringClass() != Object.class 049 && method.getReturnType() != void.class 050 && !"toString".equals(method.getName()) 051 && !"hashCode".equals(method.getName()) 052 && !"annotationType".equals(method.getName()) 053 && method.getParameterTypes().length == 0 054 && Modifier.isPublic(method.getModifiers()) 055 && !Modifier.isStatic(method.getModifiers())) { 056 try { 057 String property = method.getName(); 058 if ("interfaceClass".equals(property) || "interfaceName".equals(property)) { 059 property = "interface"; 060 } 061 String setter = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); 062 Object value = method.invoke(annotation); 063 if (value != null && !value.equals(method.getDefaultValue())) { 064 Method setterMethod = null; 065 if ("filter".equals(property) || "listener".equals(property) || "registry".equals(property)) { 066 value = StrUtil.join((String[]) value, ","); 067 setterMethod = getMethod(appendTo.getClass(), setter, String.class); 068 } else if ("parameters".equals(property)) { 069 value = CollectionUtil.string2Map((String) value); 070 setterMethod = getMethod(appendTo.getClass(), setter, Map.class); 071 } else { 072 setterMethod = getMethod(appendTo.getClass(), setter, method.getReturnType()); 073 } 074 075 //fixed : 值内容有 ${} 不生效的问题 076 if (value instanceof String) { 077 value = AnnotationUtil.get((String) value); 078 } 079 080 if (setterMethod != null) { 081 setterMethod.invoke(appendTo, value); 082 } 083 } 084 } catch (Exception ex) { 085 ex.printStackTrace(); 086 } 087 } 088 } 089 } 090 091 092 /** 093 * copy object field value to other 094 * 095 * @param copyFrom 096 * @param copyTo 097 */ 098 public static void copyDeclaredFields(Object copyFrom, Object copyTo) { 099 Field[] fields = copyFrom.getClass().getDeclaredFields(); 100 for (Field field : fields) { 101 try { 102 String setterName = "set" + StrUtil.firstCharToUpperCase(field.getName()); 103 Method method = getMethod(copyTo.getClass(), setterName, field.getType()); 104 105 if (method != null) { 106 field.setAccessible(true); 107 Object value = field.get(copyFrom); 108 if (value != null && !value.equals("0") && !value.equals("")) { 109 method.invoke(copyTo, value); 110 } 111 } 112 } catch (Exception ex) { 113 // ignore 114 } 115 } 116 } 117 118 119 private static Method getMethod(Class<?> clazz, String methodName, Class<?> type) { 120 try { 121 return clazz.getMethod(methodName, getBoxedClass(type)); 122 } catch (NoSuchMethodException e) { 123 try { 124 return clazz.getMethod(methodName, type); 125 } catch (NoSuchMethodException ex) { 126 } 127 } 128 return null; 129 } 130 131 132 public static void copyNotNullFields(Object copyFrom, Object copyTo, boolean override) { 133 if (copyFrom == null || copyTo == null) { 134 return; 135 } 136 137 Method[] fromObjGetters = copyFrom.getClass().getMethods(); 138 for (Method getter : fromObjGetters) { 139 String getterMethodName = getter.getName(); 140 if (getterMethodName.length() > 3 141 && getterMethodName.startsWith("get") 142 && Modifier.isPublic(getter.getModifiers()) 143 && getter.getParameterCount() == 0) { 144 try { 145 Class<?> returnType = getter.getReturnType(); 146 if (override) { 147 Object newData = getter.invoke(copyFrom); 148 if (newData != null) { 149 Method setter = copyTo.getClass().getMethod("set" + getterMethodName.substring(3), returnType); 150 setter.invoke(copyTo, newData); 151 } 152 } else { 153 Object oldData = copyTo.getClass().getMethod(getterMethodName).invoke(copyTo); 154 if (oldData == null) { 155 Object newData = getter.invoke(copyFrom); 156 if (newData != null) { 157 Method setter = copyTo.getClass().getMethod("set" + getterMethodName.substring(3), returnType); 158 setter.invoke(copyTo, newData); 159 } 160 } 161 } 162 } catch (Exception e) { 163 // doNothing 164 } 165 } 166 } 167 } 168 169 170 public static <T> boolean isDefaultConfigExist(Class<T> clazz, Map<String, T> ret) { 171 try { 172 Field field = clazz.getField("isDefault"); 173 field.setAccessible(true); 174 for (Object obj : ret.values()) { 175 Boolean fieldValue = (Boolean) field.get(obj); 176 if (fieldValue != null && fieldValue) { 177 return true; 178 } 179 } 180 } catch (NoSuchFieldException | IllegalAccessException e) { 181 // do nothing 182 } 183 return false; 184 } 185 186 187 188 /** 189 * 设置子节点配置,比如 ProviderConfig 下的 MethodsConfig ,或者 MethodConfig 下的 ArgumentConfig 等 190 * 191 * @param appendTo 要设置的对象 192 * @param dataSource 设置子节点的数据源 193 * @param prefix 要设置对象的配置前缀(jboot.properties 下的配置) 194 * @param arrName 要设置对象的属性名 195 * @param <T> 196 * @param <F> 197 */ 198 public static <T, F> void setChildConfig(Map<String, T> appendTo, Map<String, F> dataSource, String prefix, String arrName) { 199 if (appendTo != null && !appendTo.isEmpty()) { 200 for (Map.Entry<String, T> entry : appendTo.entrySet()) { 201 202 String configKey = "default".equals(entry.getKey()) 203 ? prefix + "." + arrName //"jboot.rpc.dubbo.method.argument" 204 : prefix + "." + entry.getKey() + "." + arrName;//"jboot.rpc.dubbo.method."+entry.getKey()+".argument"; 205 206 String configValue = Jboot.configValue(configKey, "default"); 207 List<F> argCfgList = new ArrayList<>(); 208 Set<String> arguments = StrUtil.splitToSetByComma(configValue); 209 for (String arg : arguments) { 210 F fillObj = dataSource.get(arg); 211 if (fillObj != null) { 212 argCfgList.add(fillObj); 213 } 214 } 215 if (!argCfgList.isEmpty()) { 216 try { 217 //setArguments/setMethods/setRegistries 218 String setterMethodName = arrName.equals("registry") 219 ? "setRegistries" 220 : "set" + StrUtil.firstCharToUpperCase(arrName) + "s"; 221 222 Method method = entry.getValue().getClass().getMethod(setterMethodName, List.class); 223 method.invoke(entry.getValue(), argCfgList); 224 } catch (Exception e) { 225 e.printStackTrace(); 226 } 227 } 228 } 229 } 230 } 231 232 private static Class<?> getBoxedClass(Class<?> c) { 233 if (c == int.class) { 234 c = Integer.class; 235 } else if (c == boolean.class) { 236 c = Boolean.class; 237 } else if (c == long.class) { 238 c = Long.class; 239 } else if (c == float.class) { 240 c = Float.class; 241 } else if (c == double.class) { 242 c = Double.class; 243 } else if (c == char.class) { 244 c = Character.class; 245 } else if (c == byte.class) { 246 c = Byte.class; 247 } else if (c == short.class) { 248 c = Short.class; 249 } 250 return c; 251 } 252}