/** * Generates a new instance of an anonymous inner class that implements the PageNode interface. * * @param pageClass The class providing the widget content for the page. * @param pageName The name of the page (to be used in the URL history fragment). */ private ObjectBuilder generateNewInstanceOfPageImpl(MetaClass pageClass, String pageName) { AnonymousClassStructureBuilder pageImplBuilder = ObjectBuilder.newInstanceOf( MetaClassFactory.parameterizedAs( PageNode.class, MetaClassFactory.typeParametersOf(pageClass))) .extend(); pageImplBuilder .publicMethod(String.class, "name") .append(Stmt.loadLiteral(pageName).returnValue()) .finish() .publicMethod(Class.class, "contentType") .append(Stmt.loadLiteral(pageClass).returnValue()) .finish() .publicMethod( void.class, "produceContent", Parameter.of(CreationalCallback.class, "callback")) .append( Stmt.nestedCall(Refs.get("bm")) .invoke("lookupBean", Stmt.loadLiteral(pageClass)) .invoke("getInstance", Stmt.loadVariable("callback"))) .finish(); appendPageHidingMethod(pageImplBuilder, pageClass); appendPageHiddenMethod(pageImplBuilder, pageClass); appendPageShowingMethod(pageImplBuilder, pageClass); appendPageShownMethod(pageImplBuilder, pageClass); return pageImplBuilder.finish(); }
/** * Appends the method that calls the {@code @PageHiding} method of the widget. * * @param pageImplBuilder The class builder for the implementation of PageNode we are adding the * method to. * @param pageClass The "content type" (Widget subclass) of the page. This is the type the user * annotated with {@code @Page}. */ private void appendPageHidingMethod( AnonymousClassStructureBuilder pageImplBuilder, MetaClass pageClass) { BlockBuilder<?> method = pageImplBuilder .publicMethod( void.class, createMethodNameFromAnnotation(PageHiding.class), Parameter.of(pageClass, "widget"), Parameter.of(NavigationControl.class, "control")) .body(); final MetaMethod pageHidingMethod = checkMethodAndAddPrivateAccessors( pageImplBuilder, method, pageClass, PageHiding.class, NavigationControl.class, "control"); /* * If the user did not provide a control parameter, we must proceed for them after the method is invoked. */ if (pageHidingMethod == null || pageHidingMethod.getParameters().length != 1) { method.append(Stmt.loadVariable("control").invoke("proceed")); } method.finish(); }
/** * Appends the method that calls the {@code @PageHidden} method of the widget. * * @param pageImplBuilder The class builder for the implementation of PageNode we are adding the * method to. * @param pageClass The "content type" (Widget subclass) of the page. This is the type the user * annotated with {@code @Page}. */ private void appendPageHiddenMethod( AnonymousClassStructureBuilder pageImplBuilder, MetaClass pageClass) { BlockBuilder<?> method = pageImplBuilder .publicMethod( void.class, createMethodNameFromAnnotation(PageHidden.class), Parameter.of(pageClass, "widget")) .body(); checkMethodAndAddPrivateAccessors( pageImplBuilder, method, pageClass, PageHidden.class, HistoryToken.class, "state"); if (pageClass.getAnnotation(Singleton.class) == null && pageClass.getAnnotation(ApplicationScoped.class) == null && pageClass.getAnnotation(EntryPoint.class) == null) { method.append(Stmt.loadVariable("bm").invoke("destroyBean", Stmt.loadVariable("widget"))); } method.finish(); }
private void appendPageShowMethod( AnonymousClassStructureBuilder pageImplBuilder, MetaClass pageClass, Class<? extends Annotation> annotation, boolean addPrivateAccessors) { BlockBuilder<?> method = pageImplBuilder .publicMethod( void.class, createMethodNameFromAnnotation(annotation), Parameter.of(pageClass, "widget"), Parameter.of(HistoryToken.class, "state")) .body(); int idx = 0; method.append(Stmt.declareFinalVariable("pageState", Map.class, new HashMap<String, Object>())); for (MetaField field : pageClass.getFieldsAnnotatedWith(PageState.class)) { PageState psAnno = field.getAnnotation(PageState.class); String fieldName = field.getName(); String queryParamName = psAnno.value(); if (queryParamName == null || queryParamName.trim().isEmpty()) { queryParamName = fieldName; } if (addPrivateAccessors) { PrivateAccessUtil.addPrivateAccessStubs( PrivateAccessType.Write, "jsni", pageImplBuilder, field, new Modifier[] {}); } String injectorName = PrivateAccessUtil.getPrivateFieldInjectorName(field); MetaClass erasedFieldType = field.getType().getErased(); if (erasedFieldType.isAssignableTo(Collection.class)) { MetaClass elementType = MarshallingGenUtil.getConcreteCollectionElementType(field.getType()); if (elementType == null) { throw new UnsupportedOperationException( "Found a @PageState field with a Collection type but without a concrete type parameter. " + "Collection-typed @PageState fields must specify a concrete type parameter."); } if (erasedFieldType.equals(MetaClassFactory.get(Set.class))) { method.append(Stmt.declareVariable(fieldName, Stmt.newObject(HashSet.class))); } else if (erasedFieldType.equals(MetaClassFactory.get(List.class)) || erasedFieldType.equals(MetaClassFactory.get(Collection.class))) { method.append(Stmt.declareVariable(fieldName, Stmt.newObject(ArrayList.class))); } else { throw new UnsupportedOperationException( "Found a @PageState field which is a collection of type " + erasedFieldType.getFullyQualifiedName() + ". For collection-valued fields, only the exact types java.util.Collection, java.util.Set, and " + "java.util.List are supported at this time."); } // for (String fv{idx} : state.get({fieldName})) method.append( Stmt.loadVariable("state") .invoke("getState") .invoke("get", queryParamName) .foreach("elem", Object.class) .append( Stmt.declareVariable( "fv" + idx, Stmt.castTo(String.class, Stmt.loadVariable("elem")))) .append( Stmt.loadVariable(fieldName) .invoke( "add", paramFromStringStatement(elementType, Stmt.loadVariable("fv" + idx)))) .append( Stmt.loadVariable("pageState") .invoke("put", fieldName, Stmt.loadVariable(fieldName))) .finish()); method.append( Stmt.loadVariable("this") .invoke(injectorName, Stmt.loadVariable("widget"), Stmt.loadVariable(fieldName))); } else { method.append( Stmt.declareFinalVariable( "fv" + idx, Collection.class, Stmt.loadVariable("state").invoke("getState").invoke("get", queryParamName))); method.append( If.cond( Bool.or( Bool.isNull(Stmt.loadVariable("fv" + idx)), Stmt.loadVariable("fv" + idx).invoke("isEmpty"))) .append( Stmt.loadVariable("this") .invoke( injectorName, Stmt.loadVariable("widget"), defaultValueStatement(erasedFieldType))) .finish() .else_() .append( Stmt.loadVariable("this") .invoke( injectorName, Stmt.loadVariable("widget"), paramFromStringStatement( erasedFieldType, Stmt.loadVariable("fv" + idx).invoke("iterator").invoke("next")))) .append( Stmt.loadVariable("pageState") .invoke( "put", fieldName, Stmt.loadVariable("fv" + idx).invoke("iterator").invoke("next"))) .finish()); } idx++; } if (addPrivateAccessors) { method.append( Stmt.invokeStatic( CDI.class, "fireEvent", Stmt.newObject(NavigationEvent.class) .withParameters( Stmt.newObject(PageRequest.class) .withParameters( getPageName(pageClass), Stmt.loadVariable("pageState"))))); } checkMethodAndAddPrivateAccessors( pageImplBuilder, method, pageClass, annotation, HistoryToken.class, "state"); method.finish(); }