001package net.gdface.codegen.generic; 002 003import java.lang.reflect.Modifier; 004import java.lang.reflect.TypeVariable; 005import java.util.ArrayList; 006import java.util.Arrays; 007import java.util.HashSet; 008import java.util.Iterator; 009import java.util.Set; 010import java.util.regex.Pattern; 011 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015import net.gdface.annotation.AnnotationException; 016import net.gdface.annotation.AnnotationRuntimeException; 017import net.gdface.annotation.DefaultGenericTypes; 018import net.gdface.annotation.DeriveMethod; 019import net.gdface.annotation.Generic; 020import net.gdface.annotation.GenericNameException; 021import net.gdface.annotation.GenericParam; 022import net.gdface.annotation.GenericParamException; 023import net.gdface.codegen.AnnotationUtils; 024import net.gdface.codegen.CodeGenUtils; 025import net.gdface.codegen.InvalidAnnotationDefineException; 026import net.gdface.codegen.InvalidNameException; 027import net.gdface.codegen.Method; 028import net.gdface.codegen.Method.Parameter; 029import net.gdface.codegen.NewSourceInfoAbstract; 030import net.gdface.codegen.ServiceInfo; 031import net.gdface.utils.Assert; 032 033public class GenericInterface<T> extends NewSourceInfoAbstract<T> implements GenericInterfaceConstants { 034 private static final Logger logger = LoggerFactory.getLogger(NewSourceInfoAbstract.class); 035 036 private DefaultParameterGenericTypes defaultGenericTypes; 037 038 private Class<?> shellInterface; 039 040 private ServiceInfo serviceInfo; 041 042 private boolean hasRemoteResolveType; 043 044 public GenericInterface(Class<T> interfaceClass, Class<? extends T> refClass, Class<?> shellInterface) { 045 super(interfaceClass, refClass, null); 046 Assert.notNull(shellInterface, "shellInterface"); 047 this.shellInterface=shellInterface; 048 049 if(!shellInterface.isInterface()) 050 throw new IllegalArgumentException(String.format("shellInterface must be a interface(必须是接口)")); 051 if (!interfaceClass.isAssignableFrom(shellInterface)) 052 throw new IllegalArgumentException(String.format( 053 "shellInterface must extends from [%s] (必须实现接口)", interfaceClass.getName())); 054 055 } 056 057 @Override 058 public boolean compile() { 059 boolean compileOk=false; 060 try { 061 defaultGenericTypes = new DefaultParameterGenericTypes(interfaceClass); 062 serviceInfo=new ServiceInfo(AnnotationUtils.getServiceAnnotation(shellInterface)); 063 super.compile(); 064 importedList.remove(refClass.getSimpleName()); 065 importedList.remove(interfaceClass.getSimpleName()); 066 // 检查是否有同名的泛型名称 067 for (String name : defaultGenericTypes.names()) { 068 if (hasInClassGenericTypes(name)) 069 try { 070 throw new GenericNameConflictException(name, DefaultGenericTypes.class.getSimpleName(), 071 defaultGenericTypes.toString()); 072 } catch (GenericNameConflictException e) { 073 throw new DefaultGenericTypesExceptoin(e); 074 } 075 } 076 for (Method method : methodsNeedGenerated) { 077 compile(method); 078 } 079 compileOk=true; 080 } catch (AnnotationException e) { 081 logger.error(e.toString()); 082 }catch(AnnotationRuntimeException e){ 083 logger.error(e.toString()); 084 } 085 return compileOk; 086 } 087 088 private final void compile(Method method) throws GenericParamException, GenericNameException, GenericNameConflictException { 089 for (Parameter param : method.getParameters()) { 090 try { 091 compile(param); 092 } catch (GenericParamRedefineException e) { 093 logger.warn("{} is generic type({}) defined by class,can't be redefined in method:\n{}", param.name, 094 param.genericType.toString(), method.toGenericString()); 095 } catch (GenericNameException e) { 096 throw new GenericNameException(String.format( 097 "the name of annotation %s of parameter [%s] must not have space char in method %s", 098 Generic.class.getSimpleName(), param.name, method.toGenericString())); 099 } 100 } 101 DeriveMethod deriveMethodAnnotation = getDeriveMethodAnnotation(method); 102 if(deriveMethodAnnotation!=null){ 103 this.addImportedClass(deriveMethodAnnotation.localResolvedTypes()); 104 if(deriveMethodAnnotation.remoteResolveTypes().length>0){ 105 hasRemoteResolveType=true; 106 this.addImportedClass(deriveMethodAnnotation.remoteResolveTypes()); 107 } 108 } 109 } 110 111 private final void compile(Parameter param) throws GenericParamRedefineException, GenericNameConflictException, 112 GenericNameException { 113 GenericParam genericParam = param.getAnnotation(GenericParam.class); 114 if (null != genericParam && genericParam.value() && (param.genericType instanceof TypeVariable)) { 115 throw new GenericParamRedefineException(); 116 } 117 if (null != genericParam && !genericParam.name().isEmpty()) { 118 if (!Pattern.compile("^[A-Z]\\w*$").matcher(genericParam.name()).matches()) 119 throw new GenericNameException(); 120 if (hasInClassGenericTypes(genericParam.name())) 121 throw new GenericNameConflictException(genericParam.name(), GenericParam.class.getSimpleName(), 122 genericParam.toString()); 123 } 124 } 125 126 @Override 127 protected void createMethodsNeedGenerated() { 128 ArrayList<java.lang.reflect.Method> interfaceMethods = new ArrayList<java.lang.reflect.Method>( 129 Arrays.asList(interfaceClass.getMethods())); 130 Iterator<java.lang.reflect.Method> it = interfaceMethods.iterator(); 131 try { 132 Method cm; 133 while (it.hasNext()) { 134 java.lang.reflect.Method im = it.next(); 135// cm = new Method(refClass.getMethod(im.getName(), im.getParameterTypes()), 136// this.paramTable.getParameterNames(im.getName(), im.getParameterTypes())); 137 cm = new Method(im, 138 this.paramTable.getParameterNames(im.getName(), im.getParameterTypes())); 139 140 if (needGeneric(cm)) 141 this.methodsNeedGenerated.add(cm); 142 } 143 } catch (NoSuchMethodException e) { 144 throw new RuntimeException(e); 145 } 146 } 147 148 /** 149 * @return defaultGenericTypes 150 */ 151 public DefaultParameterGenericTypes getDefaultGenericTypes() { 152 return defaultGenericTypes; 153 } 154 155 private boolean hasInClassGenericTypes(String name) { 156 for (TypeVariable<Class<T>> type : interfaceClass.getTypeParameters()) { 157 if (type.getName().equals(name)) 158 return true; 159 } 160 return false; 161 } 162 163 private final boolean hasNeedGenericParameter(Method method) { 164 for (Parameter param : method.getParameters()) { 165 if (needGeneric(param)) { 166 return true; 167 } 168 } 169 return false; 170 } 171 172 public boolean needGeneric(Method method) { 173 Generic generic = method.getAnnotation(Generic.class); 174 return (null == generic || generic.value()) && hasNeedGenericParameter(method); 175 } 176 177 public final boolean needGeneric(Parameter param){ 178 GenericParam genericParam = param.getAnnotation(GenericParam.class); 179 return (null == genericParam || genericParam.value()) && defaultGenericTypes.hasType(param.type); 180 } 181 public final GenericParam getGenericParam(Parameter param){ 182 return param.getAnnotation(GenericParam.class); 183 } 184 185 public final Set<String> getGenericNames(Method method) { 186 GenericParam genericParam; 187 Set<String> names=new HashSet<String>(); 188 for (Parameter param : method.getParameters()) { 189 if (needGeneric(param)) { 190 if(null==(genericParam = getGenericParam(param))){ 191 names.add(defaultGenericTypes.getName(param.getType())); 192 }else 193 names.add(genericParam.name()); 194 } 195 } 196 return names; 197 } 198 @Override 199 public String toString() { 200 StringBuilder builder = new StringBuilder(); 201 int c = 0; 202 builder.append("//classes need imported in new Class:\n"); 203 for (Class<?> clazz : importedList.values()) { 204 builder.append("//[" + (++c) + "]\nimported ").append(clazz.getName()).append(";\n"); 205 } 206 builder.append("public interface NewClass{\n"); 207 c = 0; 208 builder.append("//methods thad need generated in new Class:\n"); 209 for (Method m : methodsNeedGenerated) { 210 builder.append("//[" + (++c) + "]\n").append(m.toGenericString()).append(";\n"); 211 } 212 builder.append("}\n"); 213 return builder.toString(); 214 } 215 216 /** 217 * @return shellInterface 218 */ 219 public Class<?> getShellInterface() { 220 return shellInterface; 221 } 222 public DeriveMethod getDeriveMethodAnnotation(Method method) { 223 try { 224 return AnnotationUtils.getDeriveMethodAnnotation(method, serviceInfo); 225 } catch (InvalidNameException e) { 226 throw new RuntimeException(e); 227 } catch (InvalidAnnotationDefineException e) { 228 throw new RuntimeException(e); 229 } 230 } 231 232 /** 233 * @return serviceInfo 234 */ 235 public ServiceInfo getServiceInfo() { 236 return serviceInfo; 237 } 238 239 public boolean isTargetType(Class<?> type){ 240 return serviceInfo.getTargetType()==type; 241 } 242 public boolean needDeriveParam(Method method,Parameter param){ 243 DeriveMethod deriveMethod =getDeriveMethodAnnotation(method); 244 if(deriveMethod!=null){ 245 Set<String> set = CodeGenUtils.toSet(deriveMethod.genericParam()); 246 return needGeneric(param)&&(set.isEmpty()||set.contains(param.name)); 247 } 248 return false; 249 } 250 public ArrayList<String> getDeriveParameterNames(Method method){ 251 ArrayList<String> list = new ArrayList<String>(); 252 for(Parameter parameter:method.getParameters()){ 253 if(needDeriveParam(method,parameter)){ 254 list.add(parameter.name); 255 } 256 } 257 return list; 258 } 259 /** 260 * @return hasRemoteResolveType 261 */ 262 public boolean isHasRemoteResolveType() { 263 return hasRemoteResolveType; 264 } 265 266}