@Override public Collection<MetaClass> provideTypesToExpose() { final Set<MetaClass> types = new HashSet<MetaClass>(); for (final MetaClass metaClass : ClassScanner.getTypesAnnotatedWith(Remote.class)) { for (final MetaMethod method : metaClass.getDeclaredMethods()) { if (!method.getReturnType().isVoid()) { types.add(method.getReturnType().getErased()); } for (final MetaParameter parameter : method.getParameters()) { final MetaClass type = parameter.getType(); types.add(type.getErased()); final MetaParameterizedType parameterizedType = type.getParameterizedType(); if (parameterizedType != null) { for (final MetaType tp : parameterizedType.getTypeParameters()) { if (tp instanceof MetaClass) { types.add(((MetaClass) tp).getErased()); } } } } } } return types; }
/** * Returns all bindable types on the classpath. * * @param context the current generator context * @return a set of meta classes representing the all bindable types (both annotated and * configured in ErraiApp.properties). */ public static Set<MetaClass> getAllBindableTypes(final GeneratorContext context) { Collection<MetaClass> annotatedBindableTypes = ClassScanner.getTypesAnnotatedWith( Bindable.class, RebindUtils.findTranslatablePackages(context), context); Set<MetaClass> bindableTypes = new HashSet<MetaClass>(annotatedBindableTypes); bindableTypes.addAll(DataBindingUtil.getConfiguredBindableTypes()); return bindableTypes; }
private static EnvironmentConfig loadConfiguredPortableTypes() { final Map<String, String> frameworkProps = new HashMap<String, String>(); final Map<String, String> mappingAliases = new HashMap<String, String>(); final Set<MetaClass> exposedClasses = new HashSet<MetaClass>(); final Set<MetaClass> nonportableClasses = new HashSet<MetaClass>(); final Set<String> explicitTypes = new HashSet<String>(); final Set<MetaClass> portableNonExposed = new HashSet<MetaClass>(); final Set<MetaClass> exposedFromScanner = new HashSet<MetaClass>(ClassScanner.getTypesAnnotatedWith(Portable.class)); nonportableClasses.addAll(ClassScanner.getTypesAnnotatedWith(NonPortable.class)); for (final MetaClass cls : exposedFromScanner) { for (final MetaClass decl : cls.getDeclaredClasses()) { if (decl.isSynthetic()) { continue; } exposedClasses.add(decl); } } exposedClasses.addAll(exposedFromScanner); final Enumeration<URL> erraiAppProperties = getErraiAppProperties(); while (erraiAppProperties.hasMoreElements()) { InputStream inputStream = null; try { final URL url = erraiAppProperties.nextElement(); log.debug("checking " + url.getFile() + " for configured types ..."); inputStream = url.openStream(); final ResourceBundle props = new PropertyResourceBundle(inputStream); if (props != null) { for (final Object o : props.keySet()) { final String key = (String) o; frameworkProps.put(key, props.getString(key)); if (key.equals(CONFIG_ERRAI_SERIALIZABLE_TYPE)) { for (final String s : props.getString(key).split(" ")) { try { exposedClasses.add(MetaClassFactory.get(s.trim())); explicitTypes.add(s.trim()); } catch (Exception e) { throw new RuntimeException( "could not find class defined in ErraiApp.properties for serialization: " + s); } } continue; } if (key.equals(CONFIG_ERRAI_NONSERIALIZABLE_TYPE)) { for (final String s : props.getString(key).split(" ")) { try { nonportableClasses.add(MetaClassFactory.get(s.trim())); } catch (Exception e) { throw new RuntimeException( "could not find class defined in ErraiApp.properties as nonserializable: " + s); } } continue; } if (key.equals(CONFIG_ERRAI_MAPPING_ALIASES)) { for (final String s : props.getString(key).split(" ")) { try { final String[] mapping = s.split("->"); if (mapping.length != 2) { throw new RuntimeException("syntax error: mapping for marshalling alias: " + s); } final Class<?> fromMapping = Class.forName(mapping[0].trim()); final Class<?> toMapping = Class.forName(mapping[1].trim()); mappingAliases.put(fromMapping.getName(), toMapping.getName()); explicitTypes.add(fromMapping.getName()); explicitTypes.add(toMapping.getName()); } catch (Exception e) { throw new RuntimeException( "could not find class defined in ErraiApp.properties for mapping: " + s); } } continue; } } } } catch (IOException e) { throw new RuntimeException("error reading ErraiApp.properties", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // } } } } // must do this before filling in interfaces and supertypes! exposedClasses.removeAll(nonportableClasses); for (final MetaClass cls : exposedClasses) { fillInInterfacesAndSuperTypes(portableNonExposed, cls); } return new EnvironmentConfig( mappingAliases, exposedClasses, portableNonExposed, explicitTypes, frameworkProps); }
@Override protected String generate(TreeLogger logger, GeneratorContext context) { final ClassStructureBuilder<?> classBuilder = Implementations.extend(NavigationGraph.class, GENERATED_CLASS_NAME); // accumulation of (name, pageclass) mappings for dupe detection and dot file generation BiMap<String, MetaClass> pageNames = HashBiMap.create(); // accumulation UniquePageRoles for ensuring there is exactly one. Multimap<Class<?>, MetaClass> pageRoles = ArrayListMultimap.create(); ConstructorBlockBuilder<?> ctor = classBuilder.publicConstructor(); final Collection<MetaClass> pages = ClassScanner.getTypesAnnotatedWith(Page.class, context); for (MetaClass pageClass : pages) { if (!pageClass.isAssignableTo(IsWidget.class)) { throw new GenerationException( "Class " + pageClass.getFullyQualifiedName() + " is annotated with @Page, so it must implement IsWidget"); } Page annotation = pageClass.getAnnotation(Page.class); String pageName = getPageName(pageClass); List<Class<? extends PageRole>> annotatedPageRoles = Arrays.asList(annotation.role()); MetaClass prevPageWithThisName = pageNames.put(pageName, pageClass); if (prevPageWithThisName != null) { throw new GenerationException( "Page names must be unique, but " + prevPageWithThisName + " and " + pageClass + " are both named [" + pageName + "]"); } Statement pageImplStmt = generateNewInstanceOfPageImpl(pageClass, pageName); if (annotatedPageRoles.contains(DefaultPage.class)) { // need to assign the page impl to a variable and add it to the map twice ctor.append(Stmt.declareFinalVariable("defaultPage", PageNode.class, pageImplStmt)); pageImplStmt = Variable.get("defaultPage"); ctor.append(Stmt.nestedCall(Refs.get("pagesByName")).invoke("put", "", pageImplStmt)); ctor.append( Stmt.nestedCall(Refs.get("pagesByRole")) .invoke("put", DefaultPage.class, pageImplStmt)); } else if (pageName.equals("")) { throw new GenerationException( "Page " + pageClass.getFullyQualifiedName() + " has an empty path. Only the" + " page with startingPage=true is permitted to have an empty path."); } final String fieldName = StringUtils.uncapitalize(pageClass.getName()); ctor.append(Stmt.declareFinalVariable(fieldName, PageNode.class, pageImplStmt)); ctor.append( Stmt.nestedCall(Refs.get("pagesByName")).invoke("put", pageName, Refs.get(fieldName))); for (Class<? extends PageRole> annotatedPageRole : annotatedPageRoles) { pageRoles.put(annotatedPageRole, pageClass); // DefaultPage is already added above. if (!annotatedPageRole.equals(DefaultPage.class)) ctor.append( Stmt.nestedCall(Refs.get("pagesByRole")) .invoke("put", annotatedPageRole, Refs.get(fieldName))); } } ctor.finish(); renderNavigationToDotFile(pageNames); validateDefaultPagePresent(pages, pageRoles); validateUnique(pageRoles); return classBuilder.toJavaString(); }