package com.lambdaworks.apigenerator; import java.io.File; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import com.lambdaworks.redis.internal.LettuceSets; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.Type; /** * Create async API based on the templates. * * @author Mark Paluch */ @RunWith(Parameterized.class) public class CreateAsyncApi { private Set<String> KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("shutdown", "debugOom", "debugSegfault", "digest", "close", "isOpen", "BaseRedisCommands.reset", "getStatefulConnection"); private CompilationUnitFactory factory; @Parameterized.Parameters(name = "Create {0}") public static List<Object[]> arguments() { List<Object[]> result = new ArrayList<>(); for (String templateName : Constants.TEMPLATE_NAMES) { result.add(new Object[] { templateName }); } return result; } /** * @param templateName */ public CreateAsyncApi(String templateName) { String targetName = templateName.replace("Commands", "AsyncCommands"); File templateFile = new File(Constants.TEMPLATES, "com/lambdaworks/redis/api/" + templateName + ".java"); String targetPackage; if (templateName.contains("RedisSentinel")) { targetPackage = "com.lambdaworks.redis.sentinel.api.async"; } else { targetPackage = "com.lambdaworks.redis.api.async"; } factory = new CompilationUnitFactory(templateFile, Constants.SOURCES, targetPackage, targetName, commentMutator(), methodTypeMutator(), methodDeclaration -> true, importSupplier(), typeMutator(), null); } private Consumer<ClassOrInterfaceDeclaration> typeMutator() { return type -> { if (type.getName().contains("SentinelAsyncCommands")) { type.getExtends().add(new ClassOrInterfaceType("RedisSentinelAsyncConnection<K, V>")); CompilationUnit compilationUnit = (CompilationUnit) type.getParentNode(); if (compilationUnit.getImports() == null) { compilationUnit.setImports(new ArrayList<>()); } compilationUnit.getImports() .add(new ImportDeclaration(new NameExpr("com.lambdaworks.redis.RedisSentinelAsyncConnection"), false, false)); } }; } /** * Mutate type comment. * * @return */ protected Function<String, String> commentMutator() { return s -> s.replaceAll("\\$\\{intent\\}", "Asynchronous executed commands") + "* @generated by " + getClass().getName() + "\r\n "; } /** * Mutate type to async result. * * @return */ protected Function<MethodDeclaration, Type> methodTypeMutator() { return method -> { ClassOrInterfaceDeclaration classOfMethod = (ClassOrInterfaceDeclaration) method.getParentNode(); if (KEEP_METHOD_RESULT_TYPE.contains(method.getName()) || KEEP_METHOD_RESULT_TYPE.contains(classOfMethod.getName() + "." + method.getName())) { return method.getType(); } String typeAsString = method.getType().toStringWithoutComments().trim(); if (typeAsString.equals("void")) { typeAsString = "Void"; } return new ReferenceType(new ClassOrInterfaceType("RedisFuture<" + typeAsString + ">")); }; } /** * Supply additional imports. * * @return */ protected Supplier<List<String>> importSupplier() { return () -> Collections.singletonList("com.lambdaworks.redis.RedisFuture"); } @Test public void createInterface() throws Exception { factory.createInterface(); } }