package xapi.javac.dev.template; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.LiteralTree; import com.sun.source.tree.MethodInvocationTree; import xapi.annotation.inject.InstanceDefault; import xapi.collect.X_Collect; import xapi.collect.api.StringTo; import xapi.fu.Immutable; import xapi.fu.In2Out1; import xapi.fu.Out1; import xapi.inject.X_Inject; import xapi.javac.dev.api.InjectionResolver; import xapi.javac.dev.api.JavacService; import xapi.javac.dev.api.MagicMethodInjector; import xapi.source.read.JavaModel.IsType; import xapi.util.X_Debug; /** * @author James X. Nelson (james@wetheinter.net) * Created on 4/3/16. */ @InstanceDefault(implFor = TemplateInjector.class) public class TemplateInjector implements MagicMethodInjector { private static final String KEY_START = "TemplateGenerator|"; private JavacService service; private StringTo<Out1<TemplateGenerator>> generatorByTypeName; @Override public void init(JavacService service) { generatorByTypeName = X_Collect.newStringMap(Out1.class); this.service = service; service.readProperties((key, value)->{ if (key.startsWith(KEY_START)) { key = key.substring(KEY_START.length()); // TODO handle type assignability by using a much smarter map (AssignableMap, forthcoming) Class<TemplateGenerator> generator = loadClass(value); In2Out1<String, Class, TemplateGenerator> factory = this::createFactory; generatorByTypeName.put(key, factory.supply(value, generator)); } }); } private TemplateGenerator createFactory(String type, Class<TemplateGenerator> cls) { final TemplateGenerator instance = X_Inject.instance(cls); if (cacheGenerators()) { generatorByTypeName.put(type, Immutable.immutable1(instance)); } return instance; } protected boolean cacheGenerators() { return true; } private <T> Class<T> loadClass(String bit) { try { return (Class<T>) Thread.currentThread().getContextClassLoader().loadClass(bit); } catch (ClassNotFoundException e) { throw X_Debug.rethrow(e); } } @Override public boolean performInjection( CompilationUnitTree cup, MethodInvocationTree source, InjectionResolver resolver ) { final ExpressionTree template = source.getArguments().get(0); if (template instanceof LiteralTree) { LiteralTree literal = (LiteralTree) template; String value = (String) literal.getValue(); final IsType type = service.getInvocationTargetType(cup, source); TemplateGenerator generator = findGenerator(cup, source, type, value); return generator.generateTemplate(service, cup, source, type, value, resolver); } return false; } private TemplateGenerator findGenerator( CompilationUnitTree cup, MethodInvocationTree source, IsType type, String value ) { final Out1<TemplateGenerator> generator = generatorByTypeName.get(type.toString()); if (generator != null) { return generator.out1(); } return (Service, Cup, Source, Type, Value, Resolver) -> false; } }