001package net.gdface.codegen.thrift; 002 003import static com.google.common.base.Preconditions.*; 004import static net.gdface.thrift.ThriftUtils.*; 005 006import java.beans.PropertyDescriptor; 007import java.lang.reflect.Constructor; 008import java.lang.reflect.Modifier; 009import java.lang.reflect.ParameterizedType; 010import java.lang.reflect.Type; 011import java.nio.ByteBuffer; 012import java.util.ArrayDeque; 013import java.util.Deque; 014import java.util.List; 015import java.util.Map; 016import java.util.Set; 017 018import org.slf4j.Logger; 019import org.slf4j.LoggerFactory; 020 021import com.google.common.base.Function; 022import com.google.common.base.Joiner; 023import com.google.common.base.Predicate; 024import com.google.common.base.Predicates; 025import com.google.common.collect.ImmutableList; 026import com.google.common.collect.Iterables; 027import com.google.common.collect.Iterators; 028import com.google.common.collect.Lists; 029import com.google.common.collect.Maps; 030import com.google.common.collect.Sets; 031import com.google.common.primitives.Primitives; 032import com.google.common.reflect.TypeToken; 033 034import net.gdface.codegen.AbstractSchema; 035import net.gdface.codegen.Method; 036import net.gdface.codegen.Method.Parameter; 037import net.gdface.thrift.ThriftUtils; 038import net.gdface.utils.BeanPropertyUtils; 039import okio.ByteString; 040 041/** 042 * @author guyadong 043 * 044 */ 045public class TypeHelper implements ThriftConstants { 046 private static final Logger logger = LoggerFactory.getLogger(TypeHelper.class); 047 private final Set<Class<?>> knownTypes = Sets.newHashSet(); 048 private final Set<Class<?>> referTypes = Sets.newHashSet(); 049 private final Map<Class<?>,ThriftStructDecorator> decorateTypes = Maps.newHashMap(); 050 private final AbstractSchema parent; 051 private final ThreadLocal<Deque<Class<?>>> stack = new ThreadLocal<Deque<Class<?>>>() 052 { 053 @Override 054 protected Deque<Class<?>> initialValue() 055 { 056 return new ArrayDeque<>(); 057 } 058 }; 059 /** 060 * 用于外部监控所有的类型 061 */ 062 public static final ThreadLocal<Predicate<Type>> VERIFYTYPE_MONITOR = new ThreadLocal<Predicate<Type>>(); 063 public TypeHelper(AbstractSchema parent) { 064 this.parent = checkNotNull(parent,"parent is null"); 065 knownTypes.addAll(ThriftUtils.THRIFT_BUILTIN_KNOWNTYPES); 066 knownTypes.addAll(ThriftUtils.CAST_TYPES.keySet()); 067 } 068 public final boolean verifyType(Type type){ 069 if(null != VERIFYTYPE_MONITOR.get()){ 070 VERIFYTYPE_MONITOR.get().apply(type); 071 } 072 if (knownTypes.contains(type)) { 073 return true; 074 } 075 if( type instanceof ParameterizedType){ 076 ParameterizedType paramType = (ParameterizedType)type; 077 Type rawType = paramType.getRawType(); 078 Type[] typeArgs = paramType.getActualTypeArguments(); 079 if(rawType == Map.class){ 080 return verifyType(typeArgs[0]) && verifyType(typeArgs[1]); 081 }else if (rawType == List.class){ 082 return verifyType(typeArgs[0]); 083 }else if(rawType == Set.class){ 084 return verifyType(typeArgs[0]); 085 }else{ 086 throw new IllegalArgumentException(String.format("not allow parameterized type %s", type.toString())); 087 } 088 }else if(type instanceof Class){ 089 Class<?> clazz = (Class<?>)type; 090 if(null !=clazz.getDeclaringClass() && !Modifier.isStatic(clazz.getModifiers())){ 091 // 不允许为非静态成员类 092 logger.error("unsupport not static member class {}",clazz); 093 return false; 094 } 095 if(clazz.isPrimitive() || Primitives.isWrapperType(clazz)){ 096 logger.error("unsupport primitive type {}",clazz); 097 return false; 098 } 099 if(isThriftStruct(clazz)){ 100 knownTypes.add(clazz); 101 return true; 102 } 103 // 枚举类型 104 if(Enum.class.isAssignableFrom(clazz)){ 105 knownTypes.add(clazz); 106 return true; 107 } 108 // 控制只递归一层 109 if(clazz.isArray()){ 110 if(!clazz.getComponentType().isArray()){ 111 return verifyType(clazz.getComponentType()); 112 }else{ 113 logger.error("unsupport multi dimension array {}",clazz.toString()); 114 return false; 115 } 116 } 117 if(ThriftUtils.isException(clazz)){ 118 return verifyException(clazz); 119 } 120 if(Object.class == clazz){ 121 logger.error("unsupport not type Object.class"); 122 return false; 123 } 124 String pkg = clazz.getPackage().getName(); 125 if(pkg.startsWith("java.") || pkg.startsWith("javax.")){ 126 logger.error("not allow type {}",type); 127 return false; 128 } 129 return verifyStruct(clazz); 130 } 131 throw new IllegalArgumentException(String.format("not allow type %s", type.toString())); 132 } 133 private final Predicate<PropertyDescriptor> expFieldfilter= new Predicate<PropertyDescriptor>(){ 134 @Override 135 public boolean apply(PropertyDescriptor input) { 136 return input.getReadMethod().getDeclaringClass()!=Throwable.class; 137 }}; 138 private boolean verifyException(Class<?> clazz){ 139 if(!ThriftUtils.isException(clazz)){ 140 return false; 141 } 142 if(!verifyFields(clazz)){ 143 return false; 144 } 145 if(null == ThriftUtils.getConstructor(clazz) 146 && null == ThriftUtils.getConstructor(clazz,String.class)){ 147 // 没有默认构造方法也没有String参数构造方法返回false 148 logger.error("not found default constructor or consturctor with String.class argument for {}",clazz.getName()); 149 return false; 150 } 151 knownTypes.add(clazz); 152 decorateTypes.put(clazz,makeThriftStructDecorator(clazz)); 153 return true; 154 } 155 private boolean verifyStruct(Class<?> clazz){ 156 if(clazz.getTypeParameters().length > 0){ 157 logger.error("unsupport generic class {}",clazz.getName()); 158 return false; 159 } 160 try { 161 @SuppressWarnings("unused") 162 Constructor<?> ctor = clazz.getConstructor(); 163 } catch (NoSuchMethodException e) { 164 // 没有默认构造方法返回false 165 logger.error("not found default consturctor for {}",clazz.getName()); 166 return false; 167 } 168 if(!verifyFields(clazz)){ 169 return false; 170 } 171 knownTypes.add(clazz); 172 decorateTypes.put(clazz,makeThriftStructDecorator(clazz)); 173 return true; 174 } 175 private boolean verifyFields(Class<?> clazz){ 176 Map<String, PropertyDescriptor> fields = getFields(clazz); 177 for(PropertyDescriptor descriptor:fields.values()){ 178 if(!verifyType(descriptor.getReadMethod().getGenericReturnType())){ 179 logger.warn("invalid type for {} in {}",descriptor.getName(),clazz.getName()); 180 return false; 181 } 182 } 183 return true; 184 } 185 public Map<String, PropertyDescriptor> getFields(Class<?> clazz,Predicate<PropertyDescriptor>filter,boolean lenient){ 186 Map<String, PropertyDescriptor> fields = BeanPropertyUtils.getProperties(clazz, 3,lenient); 187 Predicate<PropertyDescriptor> f = checkNotNull(filter,"filter is null"); 188 if(ThriftUtils.isException(clazz) && (f != expFieldfilter)){ 189 f = Predicates.and(f, expFieldfilter); 190 } 191 return Maps.filterValues(fields, f); 192 } 193 public Map<String, PropertyDescriptor> getFields(Class<?> clazz,Predicate<PropertyDescriptor>filter){ 194 return getFields(clazz, filter, false); 195 } 196 public Map<String, PropertyDescriptor> getFields(Class<?> clazz){ 197 return getFields(clazz,Predicates.<PropertyDescriptor>alwaysTrue()); 198 } 199 public boolean isDecoratorType(Type type){ 200 return this.decorateTypes.containsKey(type); 201 } 202 public List<ThriftStructDecorator> getDecorateTypes() { 203 return ImmutableList.copyOf(decorateTypes.values()); 204 } 205 206 /** 207 * 将指定的类型转为thrift支持的类型 208 * @param type 209 * @return 210 */ 211 public String toThriftType(Type type){ 212 checkArgument(null != type,"type is null"); 213 if(ThriftUtils.THRIFT_BUILTIN_KNOWNTYPES.contains(type)){ 214 return parent.getTypeName(type); 215 } 216 if(ThriftUtils.CAST_TYPES.containsKey(type)){ 217 return parent.getTypeName(ThriftUtils.CAST_TYPES.get(type)); 218 } 219 if(this.isDecoratorType(type)){ 220 return toDecoratorType(type); 221 } 222 if( type instanceof ParameterizedType){ 223 ParameterizedType paramType = (ParameterizedType)type; 224 Type rawType = paramType.getRawType(); 225 Type[] typeArgs = paramType.getActualTypeArguments(); 226 if(rawType == Map.class){ 227 return String.format("Map<%s,%s>",toThriftType(typeArgs[0]), toThriftType(typeArgs[1])); 228 }else if (rawType == List.class){ 229 return String.format("List<%s>",toThriftType(typeArgs[0])); 230 }else if(rawType == Set.class){ 231 return String.format("Set<%s>",toThriftType(typeArgs[0])); 232 }else{ 233 throw new IllegalArgumentException(String.format("not allow parameterized type %s", type.toString())); 234 } 235 }else if(type instanceof Class){ 236 Class<?> clazz = (Class<?>)type; 237 if(clazz.isPrimitive() || Primitives.isWrapperType(clazz)){ 238 throw new IllegalArgumentException(String.format("not allow type %s", clazz.toString())); 239 } 240 if(isThriftStruct(clazz)){ 241 return parent.getTypeName(clazz); 242 } 243 // 枚举类型 244 if(Enum.class.isAssignableFrom(clazz)){ 245 return parent.getTypeName(clazz); 246 } 247 // 控制只递归一层 248 if(clazz.isArray() ){ 249 Class<?> conmponentType = clazz.getComponentType(); 250 if(!conmponentType.isArray()){ 251 return String.format("java.util.List<%s>",toThriftType(Primitives.wrap(conmponentType))); 252 }else{ 253 throw new IllegalArgumentException("unsupported type multi dimension array"); 254 } 255 } 256 } 257 throw new IllegalArgumentException(String.format("not allow type %s", type.toString())); 258 } 259 /** 260 * 将指定的类型转为thrift支持的类型(递归) 261 * @param type 262 * @return 263 */ 264 private String toClientThriftType0(Type type){ 265 checkArgument(null != type,"type is null"); 266 if(ThriftUtils.THRIFT_BUILTIN_KNOWNTYPES.contains(type) || type == Void.class ){ 267 return parent.getTypeName(type); 268 } 269 if(ThriftUtils.CAST_TYPES.containsKey(type)){ 270 return parent.getTypeName(ThriftUtils.CAST_TYPES.get(type)); 271 } 272 if( type instanceof ParameterizedType){ 273 ParameterizedType paramType = (ParameterizedType)type; 274 Type rawType = paramType.getRawType(); 275 Type[] typeArgs = paramType.getActualTypeArguments(); 276 if(rawType == Map.class){ 277 return String.format("Map<%s,%s>",toClientThriftType0(typeArgs[0]), toClientThriftType0(typeArgs[1])); 278 }else if (rawType == List.class){ 279 return String.format("List<%s>",toClientThriftType0(typeArgs[0])); 280 }else if(rawType == Set.class){ 281 return String.format("Set<%s>",toClientThriftType0(typeArgs[0])); 282 }else{ 283 throw new IllegalArgumentException(String.format("not allow parameterized type %s", type.toString())); 284 } 285 }else if(type instanceof Class){ 286 Class<?> clazz = (Class<?>)type; 287 if(clazz.isPrimitive() || Primitives.isWrapperType(clazz)){ 288 throw new IllegalArgumentException(String.format("not allow type %s", clazz.toString())); 289 } 290 if(isThriftStruct(clazz) || Enum.class.isAssignableFrom(clazz) || this.isDecoratorType(clazz)){ 291 return ThriftServiceDecoratorConfiguration.INSTANCE.getThriftClientPackage() + "." + clazz.getSimpleName(); 292 } 293 // 控制只递归一层 294 if(clazz.isArray() ){ 295 Class<?> conmponentType = clazz.getComponentType(); 296 if(!conmponentType.isArray()){ 297 return String.format("java.util.List<%s>",toClientThriftType0(Primitives.wrap(conmponentType))); 298 }else{ 299 throw new IllegalArgumentException("unsupported type multi dimension array"); 300 } 301 } 302 } 303 throw new IllegalArgumentException(String.format("not allow type %s", type.toString())); 304 } 305 /** 306 * 将指定的类型转为thrift支持的类型 307 * @param type 308 * @return 309 */ 310 public String toClientThriftType(Type type){ 311 checkArgument(null != type,"type is null"); 312 if(type == ByteBuffer.class || type == byte[].class){ 313 return parent.getTypeName(byte[].class); 314 } 315 316 return toClientThriftType0(type); 317 } 318 /** 319 * 将指定的类型转为Microsoft/thrifty支持的类型 320 * @param type 321 * @return 322 */ 323 public String toClientThriftyType(Type type){ 324 checkArgument(null != type,"type is null"); 325 if(type == ByteBuffer.class || type == byte[].class){ 326 return parent.getTypeName(ByteString.class); 327 } 328 329 return toClientThriftType0(type); 330 } 331 public String toClientThriftCxxType(Type type){ 332 return toClientThriftType(type).replaceAll("[\\.\\$]", "::"); 333 } 334 public boolean isClientThriftType(Type type){ 335 checkArgument(null != type,"type is null"); 336 if(type == ByteBuffer.class){ 337 return false; 338 } 339 if(ThriftUtils.THRIFT_BUILTIN_KNOWNTYPES.contains(type) || type == byte[].class || type == Void.class ){ 340 return true; 341 } 342 if(ThriftUtils.CAST_TYPES.containsKey(type)){ 343 return false; 344 } 345 if( type instanceof ParameterizedType){ 346 ParameterizedType paramType = (ParameterizedType)type; 347 Type rawType = paramType.getRawType(); 348 Type[] typeArgs = paramType.getActualTypeArguments(); 349 if(rawType == Map.class){ 350 return isClientThriftType(typeArgs[0]) && isClientThriftType(typeArgs[1]); 351 }else if (rawType == List.class){ 352 return isClientThriftType(typeArgs[0]); 353 }else if(rawType == Set.class){ 354 return isClientThriftType(typeArgs[0]); 355 }else{ 356 throw new IllegalArgumentException(String.format("not allow parameterized type %s", type.toString())); 357 } 358 }else if(type instanceof Class){ 359 return false; 360 } 361 throw new IllegalArgumentException(String.format("not allow type %s", type.toString())); 362 } 363 public String toDecoratorType(Type type){ 364 if(this.isDecoratorType(type)){ 365 ThriftStructDecorator decorator = decorateTypes.get(type); 366 if(decorator.getDecoratorPackage().equals(getParentPackage()) 367 && !parent.getImportedList().containsValue(type)){ 368 return ((Class<?>)type).getSimpleName(); 369 }else{ 370 return decorator.getDecoratorClassName(); 371 } 372 } 373 return parent.getTypeName(type); 374 } 375 /** 376 * 返回指定类型在thrifty client对应的装饰类名,如果非decorator,则调用{@link #toClientThriftType0(Type)} 377 * @param type 378 * @return 379 */ 380 public String toThriftyDecoratorType(Type type){ 381 if(this.isDecoratorType(type)){ 382 return toDecoratorType(type); 383 } 384 if(type == ByteBuffer.class || type == byte[].class){ 385 return parent.getTypeName(byte[].class); 386 } 387 return toClientThriftType0(type); 388 } 389 public void checkType(Type type){ 390 if(!verifyType(type)){ 391 throw new IllegalArgumentException(String.format("UNSUPPORTED TYPE %s", 392 type.toString() 393 )); 394 } 395 } 396 /** 397 * 确保方法的参数和返回类型符合要求 398 * @param method 399 */ 400 public void checkType(Method method){ 401 checkParameter(method); 402 checkReturnType(method); 403 checkThrows(method); 404 } 405 406 /** 407 * 验证参数类型 408 * @param method 409 */ 410 public void checkParameter(Method method){ 411 for (Parameter param : method.getParameters()) { 412 Type genericType = param.getGenericType(); 413 if(!verifyType(genericType)){ 414 throw new IllegalArgumentException(String.format("UNSUPPORTED TYPE %s of parameter %s in %s", 415 genericType.toString(), 416 param.name, 417 method.getName() 418 )); 419 } 420 } 421 } 422 /** 423 * 验证返回类型 424 * @param method 425 */ 426 public void checkReturnType(Method method){ 427 Type returnType = method.getGenericReturnType(); 428 if(!verifyType(returnType)){ 429 throw new IllegalArgumentException(String.format("UNSUPPORTED TYPE %s of return type for %s", 430 returnType.toString(), 431 method.getName() 432 )); 433 } 434 } 435 public void checkThrows(Method method){ 436 for(Type exp:method.getGenericExceptionTypes()){ 437 if(!verifyType(exp)){ 438 throw new IllegalArgumentException(String.format("UNSUPPORTED EXCEPTION TYPE %s in %s", 439 exp.toString(), 440 method.getName() 441 )); 442 } 443 }; 444 445 } 446 447 /** 448 * 确保{@code clazz}不是泛型类 449 * @param clazz 450 */ 451 public static void checkNotGeneric(Class<?> clazz){ 452 if(clazz.getTypeParameters().length > 0){ 453 throw new IllegalArgumentException(String.format("%s must not be a generic class", clazz.getName())); 454 } 455 } 456 /** 457 * 确保{@code method}不是泛型方法 458 * @param method 459 */ 460 public static void checkNotGeneric(java.lang.reflect.Method method){ 461 if(method.getTypeParameters().length > 0){ 462 throw new IllegalArgumentException(String.format("%s must not be a generic method", method.getName())); 463 } 464 } 465 /** 466 * 确保{@code method}不是泛型方法 467 * @param method 468 */ 469 public static void checkNotGeneric(Method method){ 470 if(method.getTypeParameters().length > 0){ 471 throw new IllegalArgumentException(String.format("%s must not be a generic method", method.getName())); 472 } 473 } 474 475 private String getParentPackage(){ 476 if(parent instanceof ThriftStructDecorator){ 477 return ((ThriftStructDecorator)parent).getDecoratorPackage(); 478 }else if(parent instanceof ThriftServiceDecorator){ 479 return ((ThriftServiceDecorator<?>)parent).getGeneratePackage(); 480 } 481 return null; 482 } 483 public void addReferTypes(Type type){ 484 traverseTypes(type,new Action(){ 485 @Override 486 public void doClass(Class<?> clazz) { 487 referTypes.add(clazz); 488 parent.addImportedClass(clazz); 489 if(CAST_TYPES.containsKey(clazz)){ 490 parent.addImportedClass(CAST_TYPES.get(clazz)); 491 referTypes.add(CAST_TYPES.get(clazz)); 492 } 493 }}); 494 } 495 public void addReferTypes(Method method){ 496 for (Parameter param : method.getParameters()) { 497 addReferTypes(param.getGenericType()); 498 } 499 addReferTypes(method.getGenericReturnType()); 500 for(Type exp:method.getGenericExceptionTypes()){ 501 addReferTypes(exp); 502 } 503 } 504 public boolean needTransformer(){ 505 return Iterators.tryFind(referTypes.iterator(), new Predicate<Class<?>>(){ 506 @Override 507 public boolean apply(Class<?> input) { 508 return ThriftUtils.needTransformer(input); 509 }}).isPresent(); 510 } 511 public List<Class<?>> getTypesWithDecorator(){ 512 return Lists.transform(getDecorateTypes(),new Function<ThriftStructDecorator,Class<?>>(){ 513 @Override 514 public Class<?> apply(ThriftStructDecorator input) { 515 return input.getBaseClass(); 516 }}); 517 } 518 public List<Class<?>> getReferExceptions(){ 519 Iterable<Class<?>> iterable = Iterables.filter(referTypes, new Predicate<Class<?>>(){ 520 @Override 521 public boolean apply(Class<?> input) { 522 return Exception.class.isAssignableFrom(input); 523 }}); 524 return Lists.newArrayList(iterable); 525 } 526 /** 527 * 创建{@link ThriftStructDecorator}实例<br> 528 * 如果{@code structType}有循环引用则抛出异常 529 * @param structType 530 * @return 531 */ 532 private ThriftStructDecorator makeThriftStructDecorator(Class<?> structType){ 533 checkNotNull(structType, "structType is null"); 534 Deque<Class<?>> stack = this.stack.get(); 535 if (stack.contains(structType)) { 536 String path = Joiner.on("->").join(Iterables.transform(Iterables.concat(stack, ImmutableList.of(structType)), new Function<Class<?>, Object>() 537 { 538 @Override 539 public Object apply(Class<?> input) 540 { 541 return TypeToken.of(input).getRawType().getName(); 542 } 543 })); 544 throw new IllegalArgumentException("Circular references are not allowed: " + path); 545 } 546 stack.push(structType); 547 try { 548 return new ThriftStructDecorator(structType); 549 } 550 finally { 551 Class<?> top = stack.pop(); 552 checkState(structType.equals(top), 553 "ThriftCatalog circularity detection stack is corrupt: expected %s, but got %s", 554 structType, 555 top); 556 } 557 } 558}