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