/** * Checks type and its supertypes for {@link ExtraTypes} annotations. * * @param type the type to examine * @param addModelExtraTypes if {@code true} the contents of the {@link #extraTypes} field will be * added to the returned list. */ private List<EntityProxyModel> checkExtraTypes(JClassType type, boolean addModelExtraTypes) throws UnableToCompleteException { Set<EntityProxyModel> toReturn = new LinkedHashSet<EntityProxyModel>(); if (addModelExtraTypes && extraTypes != null) { toReturn.addAll(extraTypes); } for (JClassType toExamine : type.getFlattenedSupertypeHierarchy()) { ExtraTypes proxyExtraTypes = toExamine.getAnnotation(ExtraTypes.class); if (proxyExtraTypes != null) { for (Class<? extends BaseProxy> clazz : proxyExtraTypes.value()) { JClassType proxy = oracle.findType(clazz.getCanonicalName()); if (proxy == null) { poison( "Unknown class %s in @%s", clazz.getCanonicalName(), ExtraTypes.class.getSimpleName()); } else { toReturn.add(getEntityProxyType(proxy)); } } } } if (toReturn.isEmpty()) { return Collections.emptyList(); } return new ArrayList<EntityProxyModel>(toReturn); }
/** Examine a RequestContext subtype to populate a ContextMethod. */ private void buildContextMethod(ContextMethod.Builder contextBuilder, JClassType contextType) throws UnableToCompleteException { Service serviceAnnotation = contextType.getAnnotation(Service.class); ServiceName serviceNameAnnotation = contextType.getAnnotation(ServiceName.class); JsonRpcService jsonRpcAnnotation = contextType.getAnnotation(JsonRpcService.class); if (serviceAnnotation == null && serviceNameAnnotation == null && jsonRpcAnnotation == null) { poison( "RequestContext subtype %s is missing a @%s or @%s annotation", contextType.getQualifiedSourceName(), Service.class.getSimpleName(), JsonRpcService.class.getSimpleName()); return; } List<RequestMethod> requestMethods = new ArrayList<RequestMethod>(); for (JMethod method : contextType.getInheritableMethods()) { if (method.getEnclosingType().equals(requestContextInterface)) { // Ignore methods declared in RequestContext continue; } RequestMethod.Builder methodBuilder = new RequestMethod.Builder(); methodBuilder.setDeclarationMethod(contextType, method); if (!validateContextMethodAndSetDataType(methodBuilder, method, jsonRpcAnnotation != null)) { continue; } requestMethods.add(methodBuilder.build()); } contextBuilder .setExtraTypes(checkExtraTypes(contextType, true)) .setRequestMethods(requestMethods); }
/** * Returns {@code true} if the type is assignable to EntityProxy or ValueProxy and has a mapping * to a domain type. * * @see * com.google.web.bindery.requestfactory.server.RequestFactoryInterfaceValidator#shouldAttemptProxyValidation() */ private boolean shouldAttemptProxyValidation(JClassType maybeProxy) { if (!entityProxyInterface.isAssignableFrom(maybeProxy) && !valueProxyInterface.isAssignableFrom(maybeProxy)) { return false; } if (maybeProxy.getAnnotation(ProxyFor.class) == null && maybeProxy.getAnnotation(ProxyForName.class) == null) { return false; } return true; }
protected void initializeDataObjects() { if (!initialized) { dataObjects = new HashMap<String, String>(); dataObjectIdentifiers = new HashMap<String, String[]>(); JClassType[] dataObjectTypes; try { initializeDefaultDataObjects(); dataObjectTypes = jClassScanner.searchClassesByAnnotation(DataObject.class); } catch (Exception e) { throw new CruxGeneratorException("Error initializing DataObjects scanner.", e); } if (dataObjectTypes != null) { for (JClassType dataClass : dataObjectTypes) { DataObject annot = dataClass.getAnnotation(DataObject.class); if (dataObjects.containsKey(annot.value())) { throw new CruxGeneratorException( "Duplicated alias for DataObject found: [" + annot.value() + "]."); } dataObjects.put(annot.value(), dataClass.getQualifiedSourceName()); dataObjectIdentifiers.put(annot.value(), extractIdentifiers(dataClass)); } } initialized = true; } }
/** * Given a UiBinder interface, return the path to its ui.xml file, suitable for any classloader to * find it as a resource. */ private static String deduceTemplateFile(MortalLogger logger, JClassType interfaceType) throws UnableToCompleteException { String templateName = null; UiTemplate annotation = interfaceType.getAnnotation(UiTemplate.class); if (annotation == null) { // if the interface is defined as a nested class, use the name of the // enclosing type if (interfaceType.getEnclosingType() != null) { interfaceType = interfaceType.getEnclosingType(); } return slashify(interfaceType.getQualifiedBinaryName()) + TEMPLATE_SUFFIX; } else { templateName = annotation.value(); if (!templateName.endsWith(TEMPLATE_SUFFIX)) { logger.die("Template file name must end with " + TEMPLATE_SUFFIX); } /* * If the template file name (minus suffix) has no dots, make it relative * to the binder's package, otherwise slashify the dots */ String unsuffixed = templateName.substring(0, templateName.lastIndexOf(TEMPLATE_SUFFIX)); if (!unsuffixed.contains(".")) { templateName = slashify(interfaceType.getPackage().getName()) + "/" + templateName; } else { templateName = slashify(unsuffixed) + TEMPLATE_SUFFIX; } } return templateName; }
private boolean isIntrospectable(TreeLogger logger, JType type) { if (type == null) { return false; } JClassType ct = type.isClassOrInterface(); if (ct != null) { if (ct.getAnnotation(Introspectable.class) != null) { return true; } for (JClassType iface : ct.getImplementedInterfaces()) { if (isIntrospectable(logger, iface)) { return true; } } if (isIntrospectable(logger, ct.getSuperclass())) { return true; } } return false; }
@Override public void createDelegates( JClassType injectableType, Collection<InjectorCreatorDelegate> delegates) { if (injectableType.getAnnotation(Templated.class) != null) { delegates.add(new InjectTemplateCreator(injectableType)); } }
protected String getRemoteServiceRelativePath() { RemoteServiceRelativePath moduleRelativeURL = serviceIntf.getAnnotation(RemoteServiceRelativePath.class); if (moduleRelativeURL != null) { return "\"" + moduleRelativeURL.value() + "\""; } return null; }
@Override public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String s) throws UnableToCompleteException { GinjectorGenerator ginjectorGenerator = new GinjectorGenerator(); JClassType clazz = generatorContext.getTypeOracle().findType(s); GinExtension[] ginExtensions = null; if (clazz.isAnnotationPresent(GinExtensions.class)) { ginExtensions = clazz.getAnnotation(GinExtensions.class).value(); } GeneratorContextWrapper gcw = new GeneratorContextWrapper(generatorContext, ginExtensions); return ginjectorGenerator.generate(treeLogger, gcw, s); }
/** * Find an annotation on a type or on one of its superclasses or superinterfaces. * * <p>This provides semantics similar to that of {@link java.lang.annotation.Inherited} except * that it checks all types to which this type is assignable. {@code @Inherited} only works on * superclasses, not superinterfaces. * * <p>Annotations present on the superclass chain will be returned preferentially over those found * in the superinterface hierarchy. Note that the annotation does not need to be tagged with * {@code @Inherited} in order to be returned from the superclass chain. * * @param annotationType the type of the annotation to look for * @return the desired annotation or <code>null</code> if the annotation is not present in the * type's type hierarchy */ public <T extends Annotation> T findAnnotationInTypeHierarchy(Class<T> annotationType) { // Remember what we've seen to avoid loops Set<JClassType> seen = new HashSet<JClassType>(); // Work queue List<JClassType> searchTypes = new LinkedList<JClassType>(); searchTypes.add(this); T toReturn = null; while (!searchTypes.isEmpty()) { JClassType current = searchTypes.remove(0); if (!seen.add(current)) { continue; } toReturn = current.getAnnotation(annotationType); if (toReturn != null) { /* * First one wins. It might be desirable at some point to have a * variation that can return more than one instance of the annotation if * it is present on multiple supertypes. */ break; } if (current.getSuperclass() != null) { // Add the superclass at the front of the list searchTypes.add(0, current.getSuperclass()); } // Superinterfaces Collections.addAll(searchTypes, current.getImplementedInterfaces()); } return toReturn; }
/** @return */ protected void initializeController(View view) { controllerName = templateParser.getTemplateController(view, baseIntf.getQualifiedSourceName(), device); String controllerClassName = ClientControllers.getController(controllerName, device); if (controllerClassName == null) { throw new CruxGeneratorException( "Error generating invoker. Controller [" + controllerName + "] not found."); } controllerClass = context.getTypeOracle().findType(controllerClassName); if (controllerClass == null) { String message = "Controller class [" + controllerName + "] , declared on view [" + view.getId() + "], could not be loaded. " + "\n Possible causes:" + "\n\t 1. Check if any type or subtype used by controller refers to another module and if this module is inherited in the .gwt.xml file." + "\n\t 2. Check if your controller or its members belongs to a client package." + "\n\t 3. Check the versions of all your modules."; throw new CruxGeneratorException(message); } Controller controllerAnnot = controllerClass.getAnnotation(Controller.class); if (controllerAnnot == null) { throw new CruxGeneratorException( "DeviceAdaptive implementation class [" + controllerClass.getQualifiedSourceName() + "] is not a valid Controller. It must be annotated with @Controller annotation."); } if (!controllerClass.isAssignableTo(deviceAdaptiveControllerClass)) { throw new CruxGeneratorException( "DeviceAdaptive implementation class [" + controllerClass.getQualifiedSourceName() + "] must externds the base class DeviceAdaptiveController."); } }
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 EntityProxyModel getEntityProxyType(JClassType entityProxyType) throws UnableToCompleteException { entityProxyType = ModelUtils.ensureBaseType(entityProxyType); EntityProxyModel toReturn = peers.get(entityProxyType); if (toReturn == null) { EntityProxyModel.Builder inProgress = peerBuilders.get(entityProxyType); if (inProgress != null) { toReturn = inProgress.peek(); } } if (toReturn == null) { EntityProxyModel.Builder builder = new EntityProxyModel.Builder(); peerBuilders.put(entityProxyType, builder); // Validate possible super-proxy types first for (JClassType supertype : entityProxyType.getFlattenedSupertypeHierarchy()) { List<EntityProxyModel> superTypes = new ArrayList<EntityProxyModel>(); if (supertype != entityProxyType && shouldAttemptProxyValidation(supertype)) { superTypes.add(getEntityProxyType(supertype)); } builder.setSuperProxyTypes(superTypes); } builder.setQualifiedBinaryName(ModelUtils.getQualifiedBaseBinaryName(entityProxyType)); builder.setQualifiedSourceName(ModelUtils.getQualifiedBaseSourceName(entityProxyType)); if (entityProxyInterface.isAssignableFrom(entityProxyType)) { builder.setType(Type.ENTITY); } else if (valueProxyInterface.isAssignableFrom(entityProxyType)) { builder.setType(Type.VALUE); } else { poison( "The type %s is not assignable to either %s or %s", entityProxyInterface.getQualifiedSourceName(), valueProxyInterface.getQualifiedSourceName()); // Cannot continue, since knowing the behavior is crucial die(poisonedMessage()); } // Get the server domain object type ProxyFor proxyFor = entityProxyType.getAnnotation(ProxyFor.class); ProxyForName proxyForName = entityProxyType.getAnnotation(ProxyForName.class); JsonRpcProxy jsonRpcProxy = entityProxyType.getAnnotation(JsonRpcProxy.class); if (proxyFor == null && proxyForName == null && jsonRpcProxy == null) { poison( "The %s type does not have a @%s, @%s, or @%s annotation", entityProxyType.getQualifiedSourceName(), ProxyFor.class.getSimpleName(), ProxyForName.class.getSimpleName(), JsonRpcProxy.class.getSimpleName()); } // Look at the methods declared on the EntityProxy List<RequestMethod> requestMethods = new ArrayList<RequestMethod>(); Map<String, JMethod> duplicatePropertyGetters = new HashMap<String, JMethod>(); for (JMethod method : entityProxyType.getInheritableMethods()) { if (method.getEnclosingType().equals(entityProxyInterface)) { // Ignore methods on EntityProxy continue; } RequestMethod.Builder methodBuilder = new RequestMethod.Builder(); methodBuilder.setDeclarationMethod(entityProxyType, method); JType transportedType; String name = method.getName(); if (JBeanMethod.GET.matches(method)) { transportedType = method.getReturnType(); String propertyName = JBeanMethod.GET.inferName(method); JMethod previouslySeen = duplicatePropertyGetters.get(propertyName); if (previouslySeen == null) { duplicatePropertyGetters.put(propertyName, method); } else { poison( "Duplicate accessors for property %s: %s() and %s()", propertyName, previouslySeen.getName(), method.getName()); } } else if (JBeanMethod.SET.matches(method) || JBeanMethod.SET_BUILDER.matches(method)) { transportedType = method.getParameters()[0].getType(); } else if (name.equals("stableId") && method.getParameters().length == 0) { // Ignore any overload of stableId continue; } else { poison("The method %s is neither a getter nor a setter", method.getReadableDeclaration()); continue; } validateTransportableType(methodBuilder, transportedType, false); RequestMethod requestMethod = methodBuilder.build(); requestMethods.add(requestMethod); } builder .setExtraTypes(checkExtraTypes(entityProxyType, false)) .setRequestMethods(requestMethods); toReturn = builder.build(); peers.put(entityProxyType, toReturn); peerBuilders.remove(entityProxyType); } return toReturn; }