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 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 * @return 272 */ 273 private String toClientThriftType0(Type type){ 274 checkArgument(null != type,"type is null"); 275 if(ThriftUtils.THRIFT_BUILTIN_KNOWNTYPES.contains(type) || type == Void.class ){ 276 return parent.getTypeName(type); 277 } 278 if(ThriftUtils.CAST_TYPES.containsKey(type)){ 279 return parent.getTypeName(ThriftUtils.CAST_TYPES.get(type)); 280 } 281 if( type instanceof ParameterizedType){ 282 ParameterizedType paramType = (ParameterizedType)type; 283 Type rawType = paramType.getRawType(); 284 Type[] typeArgs = paramType.getActualTypeArguments(); 285 if(rawType == Map.class){ 286 return String.format("Map<%s,%s>",toClientThriftType0(typeArgs[0]), toClientThriftType0(typeArgs[1])); 287 }else if (rawType == List.class){ 288 return String.format("List<%s>",toClientThriftType0(typeArgs[0])); 289 }else if(rawType == Set.class){ 290 return String.format("Set<%s>",toClientThriftType0(typeArgs[0])); 291 }else{ 292 throw new IllegalArgumentException(String.format("not allow parameterized type %s", type.toString())); 293 } 294 }else if(type instanceof Class){ 295 Class<?> clazz = (Class<?>)type; 296 if(clazz.isPrimitive() || Primitives.isWrapperType(clazz)){ 297 throw new IllegalArgumentException(String.format("not allow type %s", clazz.toString())); 298 } 299 if(isThriftStruct(clazz) || Enum.class.isAssignableFrom(clazz) || this.isDecoratorType(clazz)){ 300 return ThriftServiceDecoratorConfiguration.INSTANCE.getThriftClientPackage() + "." + clazz.getSimpleName(); 301 } 302 // 控制只递归一层 303 if(clazz.isArray() ){ 304 Class<?> conmponentType = clazz.getComponentType(); 305 if(!conmponentType.isArray()){ 306 return String.format("java.util.List<%s>",toClientThriftType0(Primitives.wrap(conmponentType))); 307 }else{ 308 throw new IllegalArgumentException("unsupported type multi dimension array"); 309 } 310 } 311 } 312 throw new IllegalArgumentException(String.format("not allow type %s", type.toString())); 313 } 314 /** 315 * 将指定的类型转为thrift支持的类型 316 * @param type 317 * @return 318 */ 319 public String toClientThriftType(Type type){ 320 checkArgument(null != type,"type is null"); 321 if(type == ByteBuffer.class || type == byte[].class){ 322 return parent.getTypeName(byte[].class); 323 } 324 325 return toClientThriftType0(type); 326 } 327 /** 328 * 将指定的类型转为Microsoft/thrifty支持的类型 329 * @param type 330 * @return 331 */ 332 public String toClientThriftyType(Type type){ 333 checkArgument(null != type,"type is null"); 334 if(type == ByteBuffer.class || type == byte[].class){ 335 return parent.getTypeName(ByteString.class); 336 } 337 338 return toClientThriftType0(type); 339 } 340 public boolean isClientThriftType(Type type){ 341 checkArgument(null != type,"type is null"); 342 if(type == ByteBuffer.class){ 343 return false; 344 } 345 if(ThriftUtils.THRIFT_BUILTIN_KNOWNTYPES.contains(type) || type == byte[].class || type == Void.class ){ 346 return true; 347 } 348 if(ThriftUtils.CAST_TYPES.containsKey(type)){ 349 return false; 350 } 351 if( type instanceof ParameterizedType){ 352 ParameterizedType paramType = (ParameterizedType)type; 353 Type rawType = paramType.getRawType(); 354 Type[] typeArgs = paramType.getActualTypeArguments(); 355 if(rawType == Map.class){ 356 return isClientThriftType(typeArgs[0]) && isClientThriftType(typeArgs[1]); 357 }else if (rawType == List.class){ 358 return isClientThriftType(typeArgs[0]); 359 }else if(rawType == Set.class){ 360 return isClientThriftType(typeArgs[0]); 361 }else{ 362 throw new IllegalArgumentException(String.format("not allow parameterized type %s", type.toString())); 363 } 364 }else if(type instanceof Class){ 365 return false; 366 } 367 throw new IllegalArgumentException(String.format("not allow type %s", type.toString())); 368 } 369 private String toDecoratorType(Type type){ 370 if(this.isDecoratorType(type)){ 371 ThriftStructDecorator decorator = decorateTypes.get(type); 372 if(decorator.getDecoratorPackage().equals(getParentPackage()) 373 && !parent.getImportedList().containsValue(type)){ 374 return ((Class<?>)type).getSimpleName(); 375 }else{ 376 return decorator.getDecoratorClassName(); 377 } 378 } 379 return parent.getTypeName(type); 380 } 381 /** 382 * 返回指定类型在thrifty client对应的装饰类名,如果非decorator,则调用{@link #toClientThriftType0(Type)} 383 * @param type 384 * @return 385 */ 386 public String toThriftyDecoratorType(Type type){ 387 if(this.isDecoratorType(type) && !Enum.class.isAssignableFrom((Class<?>) type)){ 388 return toDecoratorType(type); 389 } 390 if(type == ByteBuffer.class || type == byte[].class){ 391 return parent.getTypeName(byte[].class); 392 } 393 return toClientThriftType0(type); 394 } 395 public void checkType(Type type){ 396 if(!verifyType(type)){ 397 throw new IllegalArgumentException(String.format("UNSUPPORTED TYPE %s", 398 type.toString() 399 )); 400 } 401 } 402 /** 403 * 确保方法的参数和返回类型符合要求 404 * @param method 405 */ 406 public void checkType(Method method){ 407 checkParameter(method); 408 checkReturnType(method); 409 checkThrows(method); 410 } 411 412 /** 413 * 验证参数类型 414 * @param method 415 */ 416 public void checkParameter(Method method){ 417 for (Parameter param : method.getParameters()) { 418 Type genericType = param.getGenericType(); 419 if(!verifyType(genericType)){ 420 throw new IllegalArgumentException(String.format("UNSUPPORTED TYPE %s of parameter %s in %s", 421 genericType.toString(), 422 param.name, 423 method.getName() 424 )); 425 } 426 } 427 } 428 /** 429 * 验证返回类型 430 * @param method 431 */ 432 public void checkReturnType(Method method){ 433 Type returnType = method.getGenericReturnType(); 434 if(!verifyType(returnType)){ 435 throw new IllegalArgumentException(String.format("UNSUPPORTED TYPE %s of return type for %s", 436 returnType.toString(), 437 method.getName() 438 )); 439 } 440 } 441 public void checkThrows(Method method){ 442 for(Type exp:method.getGenericExceptionTypes()){ 443 if(!verifyType(exp)){ 444 throw new IllegalArgumentException(String.format("UNSUPPORTED EXCEPTION TYPE %s in %s", 445 exp.toString(), 446 method.getName() 447 )); 448 } 449 }; 450 451 } 452 453 /** 454 * 确保{@code clazz}不是泛型类 455 * @param clazz 456 */ 457 public static void checkNotGeneric(Class<?> clazz){ 458 if(clazz.getTypeParameters().length > 0){ 459 throw new IllegalArgumentException(String.format("%s must not be a generic class", clazz.getName())); 460 } 461 } 462 /** 463 * 确保{@code method}不是泛型方法 464 * @param method 465 */ 466 public static void checkNotGeneric(java.lang.reflect.Method method){ 467 if(method.getTypeParameters().length > 0){ 468 throw new IllegalArgumentException(String.format("%s must not be a generic method", method.getName())); 469 } 470 } 471 /** 472 * 确保{@code method}不是泛型方法 473 * @param method 474 */ 475 public static void checkNotGeneric(Method method){ 476 if(method.getTypeParameters().length > 0){ 477 throw new IllegalArgumentException(String.format("%s must not be a generic method", method.getName())); 478 } 479 } 480 481 private String getParentPackage(){ 482 if(parent instanceof ThriftStructDecorator){ 483 return ((ThriftStructDecorator)parent).getDecoratorPackage(); 484 }else if(parent instanceof ThriftServiceDecorator){ 485 return ((ThriftServiceDecorator<?>)parent).getGeneratePackage(); 486 } 487 return null; 488 } 489 public void addReferTypes(Type type){ 490 traverseTypes(type,new Action(){ 491 @Override 492 public void doClass(Class<?> clazz) { 493 referTypes.add(clazz); 494 parent.addImportedClass(clazz); 495 if(CAST_TYPES.containsKey(clazz)){ 496 parent.addImportedClass(CAST_TYPES.get(clazz)); 497 referTypes.add(CAST_TYPES.get(clazz)); 498 } 499 }}); 500 } 501 public void addReferTypes(Method method){ 502 for (Parameter param : method.getParameters()) { 503 addReferTypes(param.getGenericType()); 504 } 505 addReferTypes(method.getGenericReturnType()); 506 for(Type exp:method.getGenericExceptionTypes()){ 507 addReferTypes(exp); 508 } 509 } 510 public boolean needTransformer(){ 511 return Iterators.tryFind(referTypes.iterator(), new Predicate<Class<?>>(){ 512 @Override 513 public boolean apply(Class<?> input) { 514 return ThriftUtils.needTransformer(input); 515 }}).isPresent(); 516 } 517 public List<Class<?>> getTypesWithDecorator(){ 518 return Lists.transform(getDecorateTypes(),new Function<ThriftStructDecorator,Class<?>>(){ 519 @Override 520 public Class<?> apply(ThriftStructDecorator input) { 521 return input.getBaseClass(); 522 }}); 523 } 524 public List<Class<?>> getReferExceptions(){ 525 Iterable<Class<?>> iterable = Iterables.filter(referTypes, new Predicate<Class<?>>(){ 526 @Override 527 public boolean apply(Class<?> input) { 528 return Exception.class.isAssignableFrom(input); 529 }}); 530 return Lists.newArrayList(iterable); 531 } 532 /** 533 * 创建{@link ThriftStructDecorator}实例<br> 534 * 如果{@code structType}有循环引用则抛出异常 535 * @param structType 536 * @return 537 */ 538 private ThriftStructDecorator makeThriftStructDecorator(Class<?> structType){ 539 checkNotNull(structType, "structType is null"); 540 Deque<Class<?>> stack = this.stack.get(); 541 if (stack.contains(structType)) { 542 String path = Joiner.on("->").join(Iterables.transform(Iterables.concat(stack, ImmutableList.of(structType)), new Function<Class<?>, Object>() 543 { 544 @Override 545 public Object apply(Class<?> input) 546 { 547 return TypeToken.of(input).getRawType().getName(); 548 } 549 })); 550 throw new IllegalArgumentException("Circular references are not allowed: " + path); 551 } 552 stack.push(structType); 553 try { 554 return new ThriftStructDecorator(structType); 555 } 556 finally { 557 Class<?> top = stack.pop(); 558 checkState(structType.equals(top), 559 "ThriftCatalog circularity detection stack is corrupt: expected %s, but got %s", 560 structType, 561 top); 562 } 563 } 564}