Annotation[] extractAnnotations( TreeLogger logger, JClassType type, JMethod ifaceMethod, JMethod classMethod, GeneratorContext ctx) { Map<Class<?>, Annotation> unique = new LinkedHashMap<Class<?>, Annotation>(); // Prefer annotation on classes before interfaces. for (Annotation classAnno : classMethod.getAnnotations()) { unique.put(classAnno.annotationType(), classAnno); } // Transverse supertypes JClassType next = type.getSuperclass(); while (next != null) { JMethod method = next.findMethod(ifaceMethod.getName(), ifaceMethod.getParameterTypes()); if (method != null) for (Annotation classAnno : method.getAnnotations()) { unique.put(classAnno.annotationType(), classAnno); } next = next.getSuperclass(); } for (Annotation ifaceAnno : ifaceMethod.getAnnotations()) { unique.put(ifaceAnno.annotationType(), ifaceAnno); } return unique.values().toArray(new Annotation[unique.size()]); }
private void implementSetter( TreeLogger logger, MethodBuffer mb, JMethod method, ModelMagic manifest, HasModelFields models, Annotation[] annos) { JPrimitiveType primitive = method.getReturnType().isPrimitive(); boolean isVoid = primitive == JPrimitiveType.VOID; boolean isFluent = ModelGeneratorGwt.isFluent(method); String name = ModelGeneratorGwt.fieldName(method, manifest); ModelField field = models.getOrMakeField(name); field.addSetter( X_Source.binaryToSource(method.getReturnType().getQualifiedBinaryName()), name, ModelGeneratorGwt.toTypes(method.getParameterTypes())) .fluent = isFluent; if (!isFluent && !isVoid) { mb.println("var value = getProperty(\"" + name + "\");"); } JParameter[] params = method.getParameters(); if (params.length != 1) throw new NotConfiguredCorrectly( "A setter method, " + method.getJsniSignature() + " must have exactly one parameter"); mb.println("setProperty(\"" + name + "\", A);"); if (!isVoid) mb.println("return " + (isFluent ? "this;" : "value;")); }
private void implementAction( TreeLogger logger, ModelGenerator generator, JMethod method, ModelMagic models, Annotation[] annos) { boolean fluent = ModelGeneratorGwt.isFluent(method); JPrimitiveType primitive = method.getReturnType().isPrimitive(); if (primitive != JPrimitiveType.VOID) { if (!fluent) { // non-fluent, non-void return type is not an action // TODO change this! // implementGetter(logger, mb, method, models, annos, // method.getReturnType().getSimpleSourceName()); logger.log( Type.ERROR, "No getter for " + method.getJsniSignature() + "; " + "If your type does not use javabean getField() naming conventions, " + "then you MUST annotate a getter field with @GetterField"); } return; } MethodBuffer mb = generator.createMethod( method.getReturnType().getQualifiedSourceName(), method.getName(), ModelGeneratorGwt.typeToParameterString(method.getParameterTypes())); if (method.getName().equals("clear")) { // implement clear } if (fluent) { mb.println("return this;"); } }
@Override public void visitClientRpc(TreeLogger logger, JClassType type, ConnectorBundle bundle) throws UnableToCompleteException { checkGenericType(logger, type); Set<? extends JClassType> hierarchy = type.getFlattenedSupertypeHierarchy(); for (JClassType subType : hierarchy) { JMethod[] methods = subType.getMethods(); for (JMethod method : methods) { checkReturnType(logger, method); bundle.setNeedsInvoker(type, method); bundle.setNeedsParamTypes(type, method); if (method.getAnnotation(NoLayout.class) != null) { bundle.setMethodAttribute(type, method, MethodAttribute.NO_LAYOUT); } JType[] parameterTypes = method.getParameterTypes(); for (JType paramType : parameterTypes) { bundle.setNeedsSerialize(paramType); } } } }
public void build( TreeLogger logger, SourceBuilder<ModelMagic> builder, GeneratorContext ctx, JClassType type) throws UnableToCompleteException { ModelMagic models = builder.getPayload(); ModelGenerator generator = new ModelGenerator(builder); // Step one; determine if we already have a concrete type or not. // TODO if JClassType is final, we need to wrap it using a delegate model. JClassType concrete; // ClassBuffer cb = builder.getClassBuffer(); JClassType root = models.getRootType(logger, ctx); if (type.isInterface() == null && type != root) { concrete = type; generator.setSuperClass(type.getQualifiedSourceName()); } else { // We have an interface on our hands; search for an existing or // buildable model. // search for a supertype to inherit. Anything that extends Model, // does not implement any method we do implement, preferred type // being the one that implements the most interfaces possible final JClassType model; try { model = ctx.getTypeOracle().getType(Model.class.getName()); } catch (NotFoundException e) { logger.log( Type.ERROR, "Cannot load " + Model.class.getName() + "; " + "make sure you have xapi-gwt-model:sources.jar on classpath."); throw new UnableToCompleteException(); } concrete = model; for (JClassType supertype : concrete.getFlattenedSupertypeHierarchy()) { // Only interfaces explicitly extending Model become concrete. if (ModelGeneratorGwt.canBeSupertype(type, supertype)) { // prefer the concrete type with the most methods in common. concrete = supertype; } } if (concrete == null || concrete == model) { concrete = models.getRootType(logger, ctx); generator.setSuperClass(concrete.getQualifiedSourceName()); } else { // We have to make sure this concrete supertype is created. if (!models.hasModel(concrete.getQualifiedSourceName())) { // Concrete type is not cached. Build it now. RebindResult result = ModelGeneratorGwt.execImpl(logger, ctx, concrete.getQualifiedSourceName()); generator.setSuperClass(result.getResultTypeName()); } } } // This will probably become jsni, if we can avoid jso interface sickness... generator.createFactory(type.getQualifiedSourceName()); HasModelFields fieldMap = new HasModelFields(); fieldMap.setDefaultSerializable(type.getAnnotation(Serializable.class)); for (JMethod method : methods.keySet()) { if (!toGenerate.contains(ModelGeneratorGwt.toSignature(method))) { logger.log( Type.TRACE, "Skipping method defined in supertype: " + method.getJsniSignature()); continue; } Annotation[] annos = methods.get(method); String methodName = method.getName(); String returnType = method.getReturnType().getQualifiedSourceName(); String params = ModelGeneratorGwt.typeToParameterString(method.getParameterTypes()); // TODO: check imports if we are safe to use simple name. returnType = method.getReturnType().getSimpleSourceName(); IsType returns = X_Source.binaryToSource(method.getReturnType().getQualifiedBinaryName()); IsType[] parameters = ModelGeneratorGwt.toTypes(method.getParameterTypes()); GetterFor getter = method.getAnnotation(GetterFor.class); if (getter != null) { String name = getter.value(); if (name.length() == 0) { name = ModelUtil.stripGetter(method.getName()); } ModelField field = fieldMap.getOrMakeField(name); field.setType(returnType); assert parameters.length == 0 : "A getter method cannot have parameters. " + "Generated code requires using getter methods without args. You provided " + method.getJsniSignature(); grabAnnotations(logger, models, fieldMap, method, annos, type); field.addGetter(returns, methodName); continue; } SetterFor setter = method.getAnnotation(SetterFor.class); if (setter != null) { String name = setter.value(); if (name.length() == 0) name = ModelUtil.stripSetter(method.getName()); grabAnnotations(logger, models, fieldMap, method, annos, type); continue; } if (method.getAnnotation(DeleterFor.class) != null) { implementAction(logger, generator, method, models, annos); continue; } // No annotation. We have to guess the type. boolean isVoid = method.getReturnType().isPrimitive() == JPrimitiveType.VOID; boolean isGetter = methodName.startsWith("get") || methodName.startsWith("is") || methodName.startsWith("has"); boolean isSetter, isAction; if (isGetter) { assert !isVoid : "Cannot have a void return type with method name " + methodName + "; getter prefixes get(), is() and has() must return a type."; isSetter = false; isAction = false; } else { isSetter = methodName.startsWith("set") || methodName.startsWith("add") || methodName.startsWith("put") || methodName.startsWith("rem") || methodName.startsWith("remove"); if (isSetter) { isAction = false; } else { isAction = true; } } if (isVoid) { // definitely a setter / action method. if (isSetter) { MethodBuffer mb = generator.createMethod(returnType, methodName, params); implementSetter(logger, mb, method, models, fieldMap, annos); } else if (isAction) { implementAction(logger, generator, method, models, annos); } else { MethodBuffer mb = generator.createMethod(returnType, methodName, params); implementException(logger, mb, method); } } else { if (isGetter) { String name = ModelUtil.stripGetter(method.getName()); ModelField field = fieldMap.getOrMakeField(name); field.setType(returnType); field.addGetter(returns, methodName); grabAnnotations(logger, models, fieldMap, method, annos, type); } else if (isSetter) { MethodBuffer mb = generator.createMethod(returnType, methodName, params); implementSetter(logger, mb, method, models, fieldMap, annos); } else if (isAction) { implementAction(logger, generator, method, models, annos); } else { MethodBuffer mb = generator.createMethod(returnType, methodName, params); implementException(logger, mb, method); } } } generator.generateModel( X_Source.toType(builder.getPackage(), builder.getClassBuffer().getSimpleName()), fieldMap); }
private RequestQueueModel collectModel( TreeLogger logger, GeneratorContext context, JClassType toGenerate) throws UnableToCompleteException { RequestQueueModel.Builder rqBuilder = new RequestQueueModel.Builder(); TypeOracle typeOracle = context.getTypeOracle(); JClassType requestQueue = typeOracle.findType(RequestQueue.class.getName()); JClassType asyncCallback = typeOracle.findType(AsyncCallback.class.getName()); JClassType voidType = typeOracle.findType(Void.class.getName()); rqBuilder.setRequestQueueInterfaceName(toGenerate.getParameterizedQualifiedSourceName()); AsyncServiceModel.Builder serviceBuilder = new AsyncServiceModel.Builder(); for (JMethod m : toGenerate.getMethods()) { TreeLogger serviceLogger = logger.branch(Type.DEBUG, "Reading async service " + m.getReadableDeclaration()); // Skip those defined at RequestQueue if (m.getEnclosingType().equals(requestQueue)) { continue; } JClassType returnType = m.getReturnType().isClassOrInterface(); if (returnType == null) { serviceLogger.log(Type.ERROR, "Unexpected method return type " + returnType); throw new UnableToCompleteException(); } serviceBuilder.setAsyncServiceInterfaceName(returnType.getParameterizedQualifiedSourceName()); serviceBuilder.setDeclaredMethodName(m.getName()); Service serviceAnnotation = m.getAnnotation(Service.class); if (serviceAnnotation == null) { serviceLogger.log(Type.ERROR, "Missing @Service annotation"); throw new UnableToCompleteException(); } serviceBuilder.setService(serviceAnnotation.value().getName()); AsyncServiceMethodModel.Builder methodBuilder = new AsyncServiceMethodModel.Builder(); for (JMethod asyncMethod : m.getReturnType().isClassOrInterface().getMethods()) { TreeLogger methodLogger = serviceLogger.branch( Type.DEBUG, "Reading service method " + asyncMethod.getReadableDeclaration()); List<JType> types = new ArrayList<JType>(); methodBuilder.setReturnTypeName(voidType.getParameterizedQualifiedSourceName()); boolean asyncFound = false; for (JType param : asyncMethod.getParameterTypes()) { if (asyncFound) { methodLogger.log( Type.WARN, "Already passed an AsyncCallback param - is that what you meant?"); } if (param.isClassOrInterface() != null && param.isClassOrInterface().isAssignableTo(asyncCallback)) { JClassType boxedReturnType = ModelUtils.findParameterizationOf(asyncCallback, param.isClassOrInterface())[0]; methodBuilder .setHasCallback(true) .setReturnTypeName(boxedReturnType.getParameterizedQualifiedSourceName()); asyncFound = true; continue; // should be last, check for this... } types.add(param); } Set<JClassType> throwables = new HashSet<JClassType>(); Throws t = asyncMethod.getAnnotation(Throws.class); if (t != null) { for (Class<? extends Throwable> throwable : t.value()) { throwables.add(typeOracle.findType(throwable.getName())); } } methodBuilder .setMethodName(asyncMethod.getName()) .setArgTypes(types) .setThrowables(throwables); serviceBuilder.addMethod(methodBuilder.build()); } rqBuilder.addService(serviceBuilder.build()); } return rqBuilder.build(); }