001/** 002 * Copyright 2013 John Ericksen 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.androidtransfuse.analysis; 017 018import com.google.common.base.Function; 019import com.google.common.collect.FluentIterable; 020import com.google.common.collect.ImmutableSet; 021import com.sun.codemodel.*; 022import org.androidtransfuse.TransfuseAnalysisException; 023import org.androidtransfuse.adapter.ASTMethod; 024import org.androidtransfuse.adapter.ASTParameter; 025import org.androidtransfuse.adapter.ASTType; 026import org.androidtransfuse.adapter.ASTVoidType; 027import org.androidtransfuse.adapter.element.ASTElementFactory; 028import org.androidtransfuse.analysis.astAnalyzer.ManualSuperAspect; 029import org.androidtransfuse.experiment.*; 030import org.androidtransfuse.gen.ClassGenerationUtil; 031import org.androidtransfuse.gen.UniqueVariableNamer; 032import org.androidtransfuse.model.InjectionNode; 033import org.androidtransfuse.model.MethodDescriptor; 034 035import javax.inject.Inject; 036import java.util.Set; 037 038/** 039 * @author John Ericksen 040 */ 041public class ManualSuperGenerator implements Generation { 042 043 public static final String SUPER_NAME = "SUPER"; 044 private static final String SUPER_CALLER_CLASS_NAME = "SuperCaller"; 045 046 private final UniqueVariableNamer namer; 047 private final ClassGenerationUtil generationUtil; 048 private final ASTElementFactory astElementFactory; 049 private final ASTMethod registrationMethod; 050 051 @org.androidtransfuse.annotations.Factory 052 public interface Factory { 053 054 ManualSuperGenerator build(ASTMethod registrationMethod); 055 } 056 057 @Inject 058 public ManualSuperGenerator(UniqueVariableNamer namer, ClassGenerationUtil generationUtil, ASTElementFactory astElementFactory, ASTMethod registrationMethod) { 059 this.namer = namer; 060 this.generationUtil = generationUtil; 061 this.astElementFactory = astElementFactory; 062 this.registrationMethod = registrationMethod; 063 } 064 065 @Override 066 public void schedule(final ComponentBuilder builder, final ComponentDescriptor descriptor) { 067 068 builder.add(registrationMethod, GenerationPhase.POSTINJECTION, new ComponentMethodGenerator() { 069 @Override 070 public void generate(MethodDescriptor methodDescriptor, JBlock block) { 071 ImmutableSet<ManualSuperAspect.Method> methods = FluentIterable.from(builder.getExpressionMap().keySet()) 072 .transformAndConcat(new Function<InjectionNode, Set<ManualSuperAspect.Method>>() { 073 @Override 074 public Set<ManualSuperAspect.Method> apply(InjectionNode injectionNode) { 075 if (injectionNode.containsAspect(ManualSuperAspect.class)) { 076 ManualSuperAspect aspect = injectionNode.getAspect(ManualSuperAspect.class); 077 return aspect.getMethods(); 078 } 079 return ImmutableSet.of(); 080 } 081 }) 082 .toSet(); 083 084 try { 085 if(!methods.isEmpty()) { 086 JDefinedClass superClass = builder.getDefinedClass()._class(JMod.PUBLIC, SUPER_CALLER_CLASS_NAME); 087 088 builder.getDefinedClass().field(JMod.PUBLIC, superClass, SUPER_NAME, JExpr._new(superClass)); 089 090 for (ManualSuperAspect.Method method : methods) { 091 ASTMethod astMethod = astElementFactory.findMethod(descriptor.getType(), method.getName(), method.getParameters().toArray(new ASTType[method.getParameters().size()])); 092 093 if (astMethod != null) { 094 writeSuperCallingMethod(builder.getDefinedClass(), superClass, astMethod); 095 } 096 //todo: validation? 097 } 098 } 099 } catch (JClassAlreadyExistsException e) { 100 throw new TransfuseAnalysisException("SUPER Class already exists", e); 101 } 102 } 103 104 private void writeSuperCallingMethod(JDefinedClass target, JDefinedClass superClass, ASTMethod astMethod) { 105 JMethod superCallingMethod = superClass.method(JMod.PUBLIC, generationUtil.ref(astMethod.getReturnType()), astMethod.getName()); 106 107 JBlock body = superCallingMethod.body(); 108 JInvocation invocation = target.staticRef("super").invoke(astMethod.getName()); 109 if(astMethod.getReturnType() == ASTVoidType.VOID){ 110 body.add(invocation); 111 } 112 else{ 113 body._return(invocation); 114 } 115 116 for (ASTParameter parameter : astMethod.getParameters()) { 117 JVar param = superCallingMethod.param(generationUtil.ref(parameter.getASTType()), namer.generateName(parameter.getASTType())); 118 invocation.arg(param); 119 } 120 } 121 }); 122 123 } 124}