package com.sora.util.akatsuki; import static com.sora.util.akatsuki.SourceUtils.var; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.stream.Collectors; import javax.annotation.processing.Filer; import javax.lang.model.element.Modifier; import com.sora.util.akatsuki.models.ClassInfo; import com.sora.util.akatsuki.models.SourceClassModel; import com.sora.util.akatsuki.models.SourceCollectingModel; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; class ArgumentBuildersModel extends SourceCollectingModel<ArgumentBuilderModel> { protected ArgumentBuildersModel(ProcessorContext context, List<ArgumentBuilderModel> mappingModels) { super(context, mappingModels); } public Map<String, TypeSpec> createModel() { Map<String, List<ArgumentBuilderModel>> groupedModel = mappingModels().stream() .collect(Collectors.groupingBy(m -> m.classInfo().fullyQualifiedPackageName)); HashMap<String, TypeSpec> specHashMap = new HashMap<>(); for (Entry<String, List<ArgumentBuilderModel>> entry : groupedModel.entrySet()) { TypeSpec.Builder buildersBuilder = TypeSpec.classBuilder(Internal.BUILDER_CLASS_NAME) .addModifiers(Modifier.PUBLIC); for (ArgumentBuilderModel model : entry.getValue()) { Log.verbose(context, "direct parent:" + model.classModel().directSuperModel()); Optional<SourceClassModel> superModel = model.classModel() .directSuperModelWithAnnotation(Arg.class); if (!model.classModel().containsAnyAnnotation(Arg.class) && !superModel.isPresent()) { Log.verbose(context, "Class discarded: " + model.classInfo().className); //continue; } Log.verbose(context, "test write : " + model.classInfo().className); model.build().ifPresent(spec -> { buildersBuilder.addType(spec); Log.verbose(context, "write: " + model.classInfo().className); // abstract classes should not be built directly // TODO we need a test for this // if // (!model.classModel().containsModifier(Modifier.ABSTRACT)) // { // TODO oh well, most of our argument test are based on // abstract classes, let's do it next time buildersBuilder.addMethod(createBuilderMethod(model, spec, true).build()); buildersBuilder.addMethod(createBuilderMethod(model, spec, false).build()); // } }); } specHashMap.put(entry.getKey(), buildersBuilder.build()); } return specHashMap; } private MethodSpec.Builder createBuilderMethod(ArgumentBuilderModel model, TypeSpec builderSpec, boolean withBundle) { MethodSpec.Builder builder = MethodSpec.methodBuilder(model.classModel().simpleName()); if (withBundle) { builder.addCode("return new $L<>(bundle);", builderSpec.name) .addParameter(ClassName.get(AndroidTypes.Bundle.asMirror(context)), "bundle"); } else { builder.addCode("return new $L<>(new Bundle());", builderSpec.name); } ClassName className = ClassName.get(model.classInfo().fullyQualifiedPackageName, Internal.BUILDER_CLASS_NAME, builderSpec.name); builder.addModifiers(Modifier.PUBLIC, Modifier.STATIC).returns(ParameterizedTypeName .get(className, ClassName.get(model.classModel().originatingElement()), var("?"))); return builder; } @Override public ClassInfo classInfo() { return null; } @Override public void writeToFile(Filer filer) throws IOException { for (Entry<String, TypeSpec> entry : createModel().entrySet()) { JavaFile.builder(entry.getKey(), entry.getValue()).build().writeTo(filer); } } }