public InjectionNode generateProxy(InjectionNode injectionNode) { if (!aopProxiesGenerated.containsKey(injectionNode.getClassName())) { InjectionNode proxyInjectionNode = innerGenerateProxyCode(injectionNode); aopProxiesGenerated.put(injectionNode.getClassName(), proxyInjectionNode); } return aopProxiesGenerated.get(injectionNode.getClassName()); }
private void logInjectionNodes(InjectionNode injectionNode) { StringBuilder builder = new StringBuilder(); builder.append("Injection Nodes:\n"); InjectionNodeLogger logger = new InjectionNodeLogger(builder, injectionNode); while (logger.containsUnvisitedNodes()) { InjectionNode node = logger.next(); node.log(logger); logger.append("\n"); } log.debug(builder.toString()); }
private JInvocation buildScopeKey(InjectionNode injectionNode) { InjectionSignature signature = injectionNode.getTypeSignature(); JClass injectionNodeClassRef = generationUtil.ref(injectionNode.getASTType()); return codeModel .ref(ScopeKey.class) .staticInvoke(ScopeKey.GET_METHOD) .arg(injectionNodeClassRef.dotclass()) .arg(JExpr.lit(signature.buildScopeKeySignature())); }
@Override public void analyzeType( InjectionNode injectionNode, ASTType concreteType, AnalysisContext context) { if (injectionNode.getASTType().equals(concreteType)) { for (Class<? extends Annotation> scopeType : scopeAspectFactoryRepository.getScopes()) { if (concreteType.isAnnotated(scopeType)) { ScopeAspectFactory scopeAspectFactory = scopeAspectFactoryRepository.getScopeAspectFactory(scopeType); injectionNode.addAspect( scopeAspectFactory.buildAspect(injectionNode, concreteType, context)); } } } }
@Override public TypedExpression buildVariable( InjectionBuilderContext injectionBuilderContext, InjectionNode injectionNode) { TypedExpression providerVar = injectionExpressionBuilder.buildVariable(injectionBuilderContext, providerInjectionNode); JExpression expression = providerVar.getExpression().invoke(PROVIDER_METHOD); return typedExpressionFactory.build(injectionNode.getASTType(), expression); }
@Test public void testAnalysis() { AnalysisContext analysisContext = simpleAnalysisContextFactory.buildContext(); analysisContext.getAOPRepository().put(aopAnnotationASTType, methodInterceptorASTType); for (ASTMethod astMethod : proxyTargetASTType.getMethods()) { proxyAnalyzer.analyzeMethod( proxyTargetInjectionNode, proxyTargetASTType, astMethod, analysisContext); } assertTrue(proxyTargetInjectionNode.containsAspect(AOPProxyAspect.class)); AOPProxyAspect aspect = proxyTargetInjectionNode.getAspect(AOPProxyAspect.class); for (ASTMethod astMethod : proxyTargetASTType.getMethods()) { assertTrue(aspect.getMethodInterceptors().containsKey(astMethod)); Set<InjectionNode> interceptorInjectionNodes = aspect.getMethodInterceptors().get(astMethod); for (InjectionNode interceptorInjectionNode : interceptorInjectionNodes) { assertEquals(methodInterceptorASTType, interceptorInjectionNode.getASTType()); } } }
@Override public void analyzeField( InjectionNode injectionNode, ASTType concreteType, ASTField astField, AnalysisContext context) { if (astField.isAnnotated(NonConfigurationInstance.class)) { NonConfigurationAspect aspect = buildAspect(injectionNode); aspect.add(injectionPointFactory.buildInjectionPoint(concreteType, astField, context)); if (!injectionNode.containsAspect(ASTInjectionAspect.class)) { injectionNode.addAspect(ASTInjectionAspect.class, new ASTInjectionAspect()); } injectionNode .getAspect(ASTInjectionAspect.class) .setAssignmentType(ASTInjectionAspect.InjectionAssignmentType.FIELD); } }
private InjectionNode buildProxyInjectionNode( InjectionNode injectionNode, String proxyClassName, ASTInjectionAspect injectionAspect, ConstructorInjectionPoint proxyConstructorInjectionPoint) { InjectionNode proxyInjectionNode = new InjectionNode(new ASTProxyType(injectionNode.getASTType(), proxyClassName)); proxyInjectionNode.getAspects().putAll(injectionNode.getAspects()); // alter construction injection ASTInjectionAspect proxyInjectionAspect = new ASTInjectionAspect(); proxyInjectionAspect.addAllFieldInjectionPoints(injectionAspect.getFieldInjectionPoints()); proxyInjectionAspect.addAllMethodInjectionPoints(injectionAspect.getMethodInjectionPoints()); // replace proxy constructor because of optional interceptor construction parameters proxyInjectionAspect.add(proxyConstructorInjectionPoint); proxyInjectionAspect.setAssignmentType(injectionAspect.getAssignmentType()); proxyInjectionNode.addAspect(proxyInjectionAspect); return proxyInjectionNode; }
public TypedExpression buildVariable( InjectionBuilderContext injectionBuilderContext, InjectionNode injectionNode) { // build provider JDefinedClass providerClass = providerGenerator.generateProvider(injectionNode, true); JExpression provider = JExpr._new(providerClass).arg(injectionBuilderContext.getScopeVar()); // build scope call // <T> T getScopedObject(Class<T> clazz, Provider<T> provider); TypedExpression contextScopeHolderExpression = injectionExpressionBuilder.buildVariable(injectionBuilderContext, this.contextScopeHolder); JExpression cast = invocationHelper.coerceType(ContextScopeHolder.class, contextScopeHolderExpression); JExpression scopeVar = cast.invoke(ContextScopeHolder.GET_SCOPE); JExpression expression = scopeVar.invoke(Scope.GET_SCOPED_OBJECT).arg(buildScopeKey(injectionNode)).arg(provider); return typedExpressionFactory.build(injectionNode.getASTType(), expression); }
private InjectionNode innerGenerateProxyCode(InjectionNode injectionNode) { AOPProxyAspect aopProxyAspect = injectionNode.getAspect(AOPProxyAspect.class); JDefinedClass definedClass; String proxyClassName = injectionNode.getClassName() + "_AOPProxy"; ASTInjectionAspect injectionAspect = injectionNode.getAspect(ASTInjectionAspect.class); ConstructorInjectionPoint constructorInjectionPoint = injectionAspect.getConstructorInjectionPoint(); ConstructorInjectionPoint proxyConstructorInjectionPoint = new ConstructorInjectionPoint(ASTAccessModifier.PUBLIC); try { definedClass = codeModel._class(JMod.PUBLIC, proxyClassName, ClassType.CLASS); annotateGeneratedClass(definedClass); // extending injectionNode definedClass._extends(codeModel.ref(injectionNode.getClassName())); // copy constructor elements and add aop interceptors JMethod constructor = definedClass.constructor(JMod.PUBLIC); // converting exceptions into runtime exceptions proxyConstructorInjectionPoint.addThrows(constructorInjectionPoint.getThrowsTypes()); for (ASTType throwType : constructorInjectionPoint.getThrowsTypes()) { constructor._throws(codeModel.ref(throwType.getName())); } JBlock constructorBody = constructor.body(); List<JVar> superArguments = new ArrayList<JVar>(); for (InjectionNode node : constructorInjectionPoint.getInjectionNodes()) { String paramName = namer.generateName(node); JVar param = constructor.param(codeModel.ref(node.getClassName()), paramName); superArguments.add(param); proxyConstructorInjectionPoint.addInjectionNode(node); } // super construction JInvocation constructorInvocation = constructorBody.invoke(SUPER_REF); for (JVar paramArgument : superArguments) { constructorInvocation.arg(paramArgument); } // method interceptors Map<ASTMethod, Map<InjectionNode, JFieldVar>> interceptorFields = new HashMap<ASTMethod, Map<InjectionNode, JFieldVar>>(); for (Map.Entry<ASTMethod, Set<InjectionNode>> methodInterceptorEntry : aopProxyAspect.getMethodInterceptors().entrySet()) { buildMethodInterceptor( definedClass, proxyConstructorInjectionPoint, constructor, constructorBody, interceptorFields, methodInterceptorEntry); } } catch (JClassAlreadyExistsException e) { logger.error("JClassAlreadyExistsException while building AOP Proxy", e); } catch (ClassNotFoundException e) { logger.error("ClassNotFoundException while building AOP Proxy", e); } return buildProxyInjectionNode( injectionNode, proxyClassName, injectionAspect, proxyConstructorInjectionPoint); }
private void buildMethodInterceptor( JDefinedClass definedClass, ConstructorInjectionPoint proxyConstructorInjectionPoint, JMethod constructor, JBlock constructorBody, Map<ASTMethod, Map<InjectionNode, JFieldVar>> interceptorFields, Map.Entry<ASTMethod, Set<InjectionNode>> methodInterceptorEntry) throws ClassNotFoundException { ASTMethod method = methodInterceptorEntry.getKey(); if (method.getAccessModifier().equals(ASTAccessModifier.PRIVATE)) { throw new TransfuseAnalysisException("Unable to provide AOP on private methods"); } if (!interceptorFields.containsKey(methodInterceptorEntry.getKey())) { interceptorFields.put( methodInterceptorEntry.getKey(), new HashMap<InjectionNode, JFieldVar>()); } Map<InjectionNode, JFieldVar> injectionNodeInstanceNameMap = interceptorFields.get(methodInterceptorEntry.getKey()); // setup interceptor fields for (InjectionNode interceptorInjectionNode : methodInterceptorEntry.getValue()) { String interceptorInstanceName = namer.generateName(interceptorInjectionNode); JFieldVar interceptorField = definedClass.field( JMod.PRIVATE, codeModel.ref(interceptorInjectionNode.getClassName()), interceptorInstanceName); injectionNodeInstanceNameMap.put(interceptorInjectionNode, interceptorField); JVar interceptorParam = constructor.param( codeModel.ref(interceptorInjectionNode.getClassName()), namer.generateName(interceptorInjectionNode)); constructorBody.assign(interceptorField, interceptorParam); proxyConstructorInjectionPoint.addInjectionNode(interceptorInjectionNode); } JType returnType = codeModel.parseType(method.getReturnType().getName()); JMethod methodDeclaration = definedClass.method( method.getAccessModifier().getCodeModelJMod(), returnType, method.getName()); JBlock body = methodDeclaration.body(); // define method parameter Map<ASTParameter, JVar> parameterMap = new HashMap<ASTParameter, JVar>(); for (ASTParameter parameter : method.getParameters()) { parameterMap.put( parameter, methodDeclaration.param( JMod.FINAL, codeModel.ref(parameter.getASTType().getName()), namer.generateName(parameter.getASTType()))); } // aop interceptor Map<InjectionNode, JFieldVar> interceptorNameMap = interceptorFields.get(methodInterceptorEntry.getKey()); JArray paramArray = JExpr.newArray(codeModel.ref(Object.class)); for (ASTParameter astParameter : method.getParameters()) { paramArray.add(parameterMap.get(astParameter)); } JInvocation interceptorInvocation = buildInterceptorChain( definedClass, method, parameterMap, methodInterceptorEntry.getValue(), interceptorNameMap) .invoke("invoke"); interceptorInvocation.arg(paramArray); if (method.getReturnType().equals(ASTVoidType.VOID)) { body.add(interceptorInvocation); } else { body._return(JExpr.cast(returnType.boxify(), interceptorInvocation)); } }
private boolean isProxyRequired(InjectionNode injectionNode) { VirtualProxyAspect proxyAspect = injectionNode.getAspect(VirtualProxyAspect.class); return proxyAspect != null && proxyAspect.isProxyRequired(); }
@Test public void testBackLinkAnalysis() { ASTType astType = astClassFactory.getType(A.class); InjectionNode injectionNode = analyzer.analyze(astType, astType, analysisContext); injectionNode.addAspect(VariableBuilder.class, variableInjectionBuilderProvider.get()); // A -> B && A -> E assertEquals(1, countMethodInjectionPoints(injectionNode.getAspect(ASTInjectionAspect.class))); MethodInjectionPoint bInjectionPoint = injectionNode .getAspect(ASTInjectionAspect.class) .getGroups() .get(1) .getMethodInjectionPoints() .iterator() .next(); assertEquals(2, bInjectionPoint.getInjectionNodes().size()); // A -> B InjectionNode bInjectionNode = bInjectionPoint.getInjectionNodes().get(0); assertTrue(isProxyRequired(bInjectionNode)); assertEquals(BImpl.class.getCanonicalName(), bInjectionNode.getClassName()); // A -> E InjectionNode eInjectionNode = bInjectionPoint.getInjectionNodes().get(1); assertFalse(isProxyRequired(eInjectionNode)); assertEquals(E.class.getCanonicalName(), eInjectionNode.getClassName()); // B -> C assertEquals(1, countFieldInjectionPoints(bInjectionNode.getAspect(ASTInjectionAspect.class))); FieldInjectionPoint cInjectionPoint = bInjectionNode .getAspect(ASTInjectionAspect.class) .getGroups() .get(1) .getFieldInjectionPoints() .iterator() .next(); InjectionNode cInjectionNode = cInjectionPoint.getInjectionNode(); assertFalse(isProxyRequired(cInjectionNode)); assertEquals(C.class.getCanonicalName(), cInjectionNode.getClassName()); // B -> F ConstructorInjectionPoint fNonBackLinkInjectionPoint = bInjectionNode.getAspect(ASTInjectionAspect.class).getConstructorInjectionPoint(); assertEquals(1, fNonBackLinkInjectionPoint.getInjectionNodes().size()); InjectionNode fInjectionNode = fNonBackLinkInjectionPoint.getInjectionNodes().get(0); assertFalse(isProxyRequired(fInjectionNode)); assertEquals(F.class.getCanonicalName(), fInjectionNode.getClassName()); // E -> F ConstructorInjectionPoint fNonBackLinkInjectionPoint2 = eInjectionNode.getAspect(ASTInjectionAspect.class).getConstructorInjectionPoint(); assertEquals(1, fNonBackLinkInjectionPoint2.getInjectionNodes().size()); InjectionNode fInjectionNode2 = fNonBackLinkInjectionPoint2.getInjectionNodes().get(0); assertFalse(isProxyRequired(fInjectionNode2)); // C -> D assertEquals(1, countFieldInjectionPoints(cInjectionNode.getAspect(ASTInjectionAspect.class))); FieldInjectionPoint dInjectionPoint = cInjectionNode .getAspect(ASTInjectionAspect.class) .getGroups() .get(1) .getFieldInjectionPoints() .iterator() .next(); InjectionNode dInjectionNode = dInjectionPoint.getInjectionNode(); assertFalse(isProxyRequired(dInjectionNode)); assertEquals(D.class.getCanonicalName(), dInjectionNode.getClassName()); // D -> B back link ConstructorInjectionPoint bBackLinkInjectionPoint = dInjectionNode.getAspect(ASTInjectionAspect.class).getConstructorInjectionPoint(); assertEquals(1, bBackLinkInjectionPoint.getInjectionNodes().size()); InjectionNode bBackLinkInjectionNode = bBackLinkInjectionPoint.getInjectionNodes().get(0); assertEquals(BImpl.class.getCanonicalName(), bBackLinkInjectionNode.getClassName()); assertTrue(isProxyRequired(bBackLinkInjectionNode)); // B -> F and E -> F difference assertNotSame(fInjectionNode, fInjectionNode2); assertFalse(fInjectionNode.equals(fInjectionNode2)); }
private NonConfigurationAspect buildAspect(InjectionNode injectionNode) { if (!injectionNode.containsAspect(NonConfigurationAspect.class)) { injectionNode.addAspect(new NonConfigurationAspect()); } return injectionNode.getAspect(NonConfigurationAspect.class); }