001package net.gdface.codegen.thrift; 002 003import net.gdface.codegen.AbstractSchema; 004import net.gdface.codegen.thrift.ThriftServiceDecoratorConfiguration.LanguageType; 005import net.gdface.thrift.ThriftDecorator; 006import net.gdface.thrift.ThriftUtils; 007import net.gdface.thrift.TypeTransformer; 008import net.gdface.utils.NameStringUtils; 009 010import static com.google.common.base.Preconditions.*; 011 012import java.beans.PropertyDescriptor; 013import java.lang.reflect.Type; 014import java.util.Collections; 015import java.util.Comparator; 016import java.util.List; 017import java.util.Map; 018import java.util.Map.Entry; 019 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022 023import com.google.common.base.Function; 024import com.google.common.base.Predicate; 025import com.google.common.base.Predicates; 026import com.google.common.collect.ImmutableList; 027import com.google.common.collect.ImmutableMap; 028import com.google.common.collect.Iterables; 029import com.google.common.collect.Maps; 030 031/** 032 * 装饰类信息 033 * @author guyadong 034 * 035 */ 036public class ThriftStructDecorator extends AbstractSchema implements ThriftConstants,Comparator<ThriftStructDecorator>,Comparable<ThriftStructDecorator>{ 037 private static final Logger logger = LoggerFactory.getLogger(ThriftStructDecorator.class); 038 039 private final Map<String, PropertyDescriptor> fields; 040 private final String decoratorPackage; 041 private final String decoratorClassName; 042 private final TypeHelper typeHelper = new TypeHelper(this); 043 044 private final Map<String, CxxType> cxxFields; 045 046 private final boolean hasOptional; 047 private final boolean hasCanMove; 048 049 private final CxxType cxxType; 050 051 private final TraverseTypeForTryFind findString= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){ 052 @Override 053 public boolean apply(CxxTypeMeta input) { 054 return null != input && (input.isBinary() || input.isString()); 055 }}); 056 private final TraverseTypeForTryFind findMap= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){ 057 @Override 058 public boolean apply(CxxTypeMeta input) { 059 return null != input && input.isMap(); 060 }}); 061 private final TraverseTypeForTryFind findSet= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){ 062 @Override 063 public boolean apply(CxxTypeMeta input) { 064 return null != input && input.isSet(); 065 }}); 066 private final TraverseTypeForTryFind findArray= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){ 067 @Override 068 public boolean apply(CxxTypeMeta input) { 069 return null != input && input.isList(); 070 }}); 071 /** 072 * 对{@code baseClass}生成装饰类 073 * @param baseClass 074 */ 075 public ThriftStructDecorator(Class<? > baseClass) { 076 this.baseClass = checkNotNull(baseClass); 077 TypeHelper.checkNotGeneric(baseClass); 078 if(baseClass.isInterface()){ 079 throw new IllegalArgumentException("baseClass must not be interface"); 080 } 081 fields = ImmutableMap.copyOf(typeHelper.getFields(baseClass,Predicates.<PropertyDescriptor>alwaysTrue(),true)); 082 hasOptional = Iterables.tryFind(fields.values(), new Predicate<PropertyDescriptor>(){ 083 @Override 084 public boolean apply(PropertyDescriptor input) { 085 return !input.getReadMethod().getReturnType().isPrimitive(); 086 }}).isPresent(); 087 088 cxxFields=LanguageType.CPP.equals(LanguageType.getCurrent()) 089 ? getThriftTypes(fields) 090 : Collections.<String, CxxType>emptyMap(); 091 cxxType = CxxType.getThriftType(getBaseClass()); 092 hasCanMove = Iterables.tryFind(cxxFields.values(), new Predicate<CxxType>(){ 093 @Override 094 public boolean apply(CxxType input) { 095 return input.getStubType().isCanMove(); 096 }}).isPresent(); 097 StringBuffer buffer = new StringBuffer(baseClass.getPackage().getName()); 098 if(LanguageType.JAVA.equals(LanguageType.getCurrent())){ 099 buffer.append( "." + ThriftUtils.DECORATOR_PKG_SUFFIX); 100 switch(ThriftServiceDecoratorConfiguration.INSTANCE.getTaskType()){ 101 case CLIENT: 102 buffer.append(".").append(ThriftUtils.CLIENT_SUFFIX);break; 103 case CLIENT_THRIFTY: 104 buffer.append(".").append(ThriftUtils.CLIENT_SUFFIX);break; 105 default: 106 break; 107 } 108 } 109 decoratorPackage = buffer.toString(); 110 decoratorClassName = decoratorPackage + "." + this.baseClass.getSimpleName(); 111 } 112 @Override 113 public boolean compile() { 114 // 循环扫描检查所有的引用类型 115 for(Entry<String, PropertyDescriptor> entry:fields.entrySet()){ 116 PropertyDescriptor descriptor = entry.getValue(); 117 Type returnType = descriptor.getReadMethod().getGenericReturnType(); 118 typeHelper.checkType(returnType); 119 typeHelper.addReferTypes(returnType); 120 if(NameStringUtils.isThriftReserved( descriptor.getName())){ 121 logger.warn("field name '{}' of {} is thrift IDL reserved word", descriptor.getName(),this.getBaseClass().getName()); 122 } 123 if(NameStringUtils.isJavaReserved( descriptor.getName())){ 124 logger.warn("field name '{}' of {} is java reserved word", descriptor.getName(),this.getBaseClass().getName()); 125 } 126 } 127 if(typeHelper.needTransformer()){ 128 addImportedClass(TypeTransformer.class); 129 } 130 addImportedClass(ThriftDecorator.class); 131 132 return true; 133 } 134 public String getGetMethodName(String field){ 135 PropertyDescriptor descriptor = getField(field); 136 return descriptor.getReadMethod().getName(); 137 } 138 public String getSetMethodName(String field){ 139 PropertyDescriptor descriptor = getField(field); 140 return descriptor.getWriteMethod().getName(); 141 } 142 143 public Type getFieldType(String field){ 144 PropertyDescriptor descriptor = getField(field); 145 return descriptor.getReadMethod().getGenericReturnType(); 146 } 147 148 public PropertyDescriptor getField(String field){ 149 PropertyDescriptor descriptor = fields.get(field); 150 if(null == descriptor){ 151 throw new IllegalArgumentException(String.format("INVALID field %s in %s", field,this.baseClass.getSimpleName())); 152 } 153 return descriptor; 154 } 155 156 public List<String> getFields(){ 157 return ImmutableList.copyOf(this.fields.keySet()); 158 } 159 public List<PropertyDescriptor> getFieldDescriptors(){ 160 return ImmutableList.copyOf(this.fields.values()); 161 } 162 public String getDecoratorPackage() { 163 return decoratorPackage; 164 } 165 166 public String getDecoratorClassName() { 167 return decoratorClassName; 168 } 169 170 public List<ThriftStructDecorator> getDecorateTypes() { 171 return typeHelper.getDecorateTypes(); 172 } 173 174 public boolean isDecoratorType(Type type) { 175 return typeHelper.isDecoratorType(type); 176 } 177 178 public boolean isException(){ 179 return Exception.class.isAssignableFrom(getBaseClass()); 180 } 181 public boolean isEnum(){ 182 return Enum.class.isAssignableFrom(getBaseClass()); 183 } 184 public boolean isBean(){ 185 return !isException() && !isEnum(); 186 } 187 public boolean hasStringConstructor(){ 188 return ThriftUtils.hasConstructor(getBaseClass(), String.class); 189 } 190 public String toThriftType(Type type) { 191 return typeHelper.toThriftType(type); 192 } 193 194 public String toClientThriftType(Type type) { 195 return typeHelper.toClientThriftType(type); 196 } 197 public String toClientThriftyType(Type type) { 198 return typeHelper.toClientThriftyType(type); 199 } 200 201 public String toDecoratorType(Type type) { 202 return typeHelper.toDecoratorType(type); 203 } 204 205 public String toThriftyDecoratorType(Type type) { 206 return typeHelper.toThriftyDecoratorType(type); 207 } 208 @Override 209 public int hashCode() { 210 final int prime = 31; 211 int result = 1; 212 result = prime * result + ((baseClass == null) ? 0 : baseClass.hashCode()); 213 return result; 214 } 215 216 @Override 217 public boolean equals(Object obj) { 218 if (this == obj) 219 return true; 220 if (obj == null) 221 return false; 222 if (!(obj instanceof ThriftStructDecorator)) 223 return false; 224 ThriftStructDecorator other = (ThriftStructDecorator) obj; 225 if (baseClass == null) { 226 if (other.baseClass != null) 227 return false; 228 } else if (!baseClass.equals(other.baseClass)) 229 return false; 230 return true; 231 } 232 233 @Override 234 public String toString() { 235 StringBuilder builder = new StringBuilder(); 236 builder.append("ThriftStructDecorator [baseClass="); 237 builder.append(baseClass); 238 builder.append("]"); 239 return builder.toString(); 240 } 241 public void removeDecorateTypesFromImports(){ 242 this.removeClassFromImports(typeHelper.getTypesWithDecorator()); 243 } 244 245 @Override 246 public int compare(ThriftStructDecorator o1, ThriftStructDecorator o2) { 247 return o1.getBaseClass().getSimpleName().compareTo(o2.getBaseClass().getSimpleName()); 248 } 249 250 @Override 251 public int compareTo(ThriftStructDecorator o) { 252 return getBaseClass().getSimpleName().compareTo(o.getBaseClass().getSimpleName()); 253 } 254 255 private static ImmutableMap<String, CxxType> getThriftTypes(Map<String, PropertyDescriptor> fields){ 256 Map<String, CxxType> m = Maps.transformValues(checkNotNull(fields,"fields is null"), 257 new Function<PropertyDescriptor,CxxType>(){ 258 @Override 259 public CxxType apply(PropertyDescriptor input) { 260 return CxxType.getThriftType(input.getReadMethod().getGenericReturnType()); 261 } 262 }); 263 return ImmutableMap.copyOf(m); 264 } 265 public ImmutableMap<String, CxxType> getCxxFieldsAsMap(){ 266 return ImmutableMap.copyOf(this.cxxFields); 267 } 268 public CxxType getCxxField(String name){ 269 return cxxFields.get(checkNotNull(name,"name is null")); 270 } 271 /** 272 * 是否有optional字段 273 * @return 274 */ 275 public boolean isHasOptionalField(){ 276 return hasOptional; 277 } 278 279 /** 280 * 是否有需要移动的字段 281 * @return 282 */ 283 public boolean isHasCanMoveField() { 284 return hasCanMove; 285 } 286 public CxxType getCxxType() { 287 return cxxType; 288 } 289 290 private static class TraverseTypeForTryFind implements Predicate<CxxType>{ 291 private Predicate<CxxTypeMeta> finder; 292 TraverseTypeForTryFind(Predicate<CxxTypeMeta> finder){ 293 this.finder = finder; 294 } 295 @Override 296 public boolean apply(CxxType input) { 297 if(null == input){ 298 return false; 299 } 300 CxxTypeMeta type = input.getUiType(); 301 if(finder.apply(type)){ 302 return true; 303 } 304 if(type.isContainer()){ 305 CxxTypeMeta keyType = type.getKeyType(); 306 CxxTypeMeta valueType = type.getValueType(); 307 if(null != keyType && finder.apply(keyType)){ 308 return true; 309 } 310 if(null != valueType && finder.apply(valueType)){ 311 return true; 312 } 313 } 314 return false; 315 }} 316 public boolean isUseString(){ 317 return Iterables.tryFind(cxxFields.values(), findString).isPresent(); 318 } 319 public boolean isUseMap(){ 320 return Iterables.tryFind(cxxFields.values(), findMap).isPresent(); 321 } 322 public boolean isUseSet(){ 323 return Iterables.tryFind(cxxFields.values(), findSet).isPresent(); 324 } 325 public boolean isUseVector(){ 326 return Iterables.tryFind(cxxFields.values(), findArray).isPresent(); 327 } 328}