BuildMetaClass make(final String proxyClassName, final MetaClass toProxy, final String privateAccessorType) { final ClassStructureBuilder builder; final boolean renderEqualsAndHash; if (!toProxy.isInterface()) { renderEqualsAndHash = true; if (toProxy.isFinal()) { throw new UnproxyableClassException(toProxy, toProxy.getFullyQualifiedName() + " is an unproxiable class because it is final"); } if (!toProxy.isDefaultInstantiable()) { throw new UnproxyableClassException(toProxy, toProxy.getFullyQualifiedName() + " must have a default " + "no-arg constructor"); } builder = ClassBuilder.define(proxyClassName, toProxy).publicScope().body(); } else { renderEqualsAndHash = false; builder = ClassBuilder.define(proxyClassName).publicScope().implementsInterface(toProxy).body(); } final String proxyVar = "$$_proxy_$$"; final Set<String> renderedMethods = new HashSet<String>(); final Map<String, MetaType> typeVariableMap = new HashMap<String, MetaType>(); final MetaParameterizedType metaParameterizedType = toProxy.getParameterizedType(); if (metaParameterizedType != null) { int i = 0; for (final MetaTypeVariable metaTypeVariable : toProxy.getTypeParameters()) { typeVariableMap.put(metaTypeVariable.getName(), metaParameterizedType.getTypeParameters()[i++]); } } builder.privateField(proxyVar, toProxy).finish(); final Set<Map.Entry<String, ProxyProperty>> entries = proxyProperties.entrySet(); for (final Map.Entry<String, ProxyProperty> entry : entries) { builder.privateField(entry.getValue().getEncodedProperty(), entry.getValue().getType()).finish(); builder.packageMethod(void.class, "$set_" + entry.getKey(), Parameter.of(entry.getValue().getType(), "o")) .append(Stmt.loadVariable(entry.getValue().getEncodedProperty()).assignValue(Refs.get("o"))) .finish(); } for (final MetaMethod method : toProxy.getMethods()) { final String methodString = GenUtil.getMethodString(method); if (renderedMethods.contains(methodString) || method.getName().equals("hashCode") || (method.getName().equals("equals") && method.getParameters().length == 1 && method.getParameters()[0].getType().getFullyQualifiedName().equals(Object.class.getName()))) continue; renderedMethods.add(methodString); if ((!method.isPublic() && !method.isProtected()) || method.isSynthetic() || method.isFinal() || method.isStatic() || method.getDeclaringClass().getFullyQualifiedName().equals(Object.class.getName())) continue; final List<Parameter> methodParms = new ArrayList<Parameter>(); final MetaParameter[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) { methodParms.add(Parameter.of(parameters[i].getType().getErased(), "a" + i)); } final DefParameters defParameters = DefParameters.fromParameters(methodParms); final BlockBuilder methBody = builder.publicMethod(method.getReturnType(), method.getName()) .annotatedWith(OVERRIDE_ANNOTATION) .parameters(defParameters) .throws_(method.getCheckedExceptions()); methBody.appendAll(getAroundInvokeStatements(method)); methBody.appendAll(getBeforeStatements(method)); final List<Parameter> parms = defParameters.getParameters(); final Statement[] statementVars = new Statement[parms.size()]; for (int i = 0; i < parms.size(); i++) { statementVars[i] = loadVariable(parms.get(i).getName()); } if (!method.isPublic()) { PrivateAccessUtil.addPrivateAccessStubs(privateAccessorType, builder, method, new Modifier[0]); final Statement[] privateAccessStmts = new Statement[statementVars.length + 1]; privateAccessStmts[0] = Refs.get(proxyVar); System.arraycopy(statementVars, 0, privateAccessStmts, 1, statementVars.length); if (method.getReturnType().isVoid()) { methBody._(loadVariable("this").invoke(PrivateAccessUtil.getPrivateMethodName(method), privateAccessStmts)); } else { methBody._(loadVariable("this").invoke(PrivateAccessUtil.getPrivateMethodName(method), privateAccessStmts).returnValue()); } } else { if (method.getReturnType().isVoid()) { methBody._(loadVariable(proxyVar).invoke(method, statementVars)); } else { methBody._(loadVariable(proxyVar).invoke(method, statementVars).returnValue()); } } methBody.appendAll(getAfterStatements(method)); methBody.appendAll(getAroundInvokeStatements(method)); methBody.finish(); } if (renderEqualsAndHash) { // implement hashCode() builder.publicMethod(int.class, "hashCode") .annotatedWith(OVERRIDE_ANNOTATION) .body() ._( If.isNull(loadVariable(proxyVar)) ._(throw_(IllegalStateException.class, "call to hashCode() on an unclosed proxy.")) .finish() .else_() ._(Stmt.loadVariable(proxyVar).invoke("hashCode").returnValue()) .finish() ) .finish(); // implements equals() builder.publicMethod(boolean.class, "equals", Parameter.of(Object.class, "o")) .annotatedWith(OVERRIDE_ANNOTATION) .body() ._( If.isNull(loadVariable(proxyVar)) ._(throw_(IllegalStateException.class, "call to equals() on an unclosed proxy.")) .finish() .else_() ._(Stmt.loadVariable(proxyVar).invoke("equals", Refs.get("o")).returnValue()) .finish() ) .finish(); } builder.publicMethod(void.class, PROXY_BIND_METHOD).parameters(DefParameters.of(Parameter.of(toProxy, "proxy"))) ._(loadVariable(proxyVar).assignValue(loadVariable("proxy"))).finish(); return builder.getClassDefinition(); }
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(); }