/* * Copyright (C) 2017 The Dagger Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dagger.internal.codegen.writing; import static com.squareup.javapoet.MethodSpec.constructorBuilder; import static com.squareup.javapoet.MethodSpec.methodBuilder; import static com.squareup.javapoet.TypeSpec.classBuilder; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; import static javax.lang.model.element.Modifier.PRIVATE; import com.google.common.collect.ImmutableList; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; import dagger.internal.codegen.base.SourceFileGenerator; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; /** * A source file generator that only writes the relevant code necessary for Bazel to create a * correct header (ABI) jar. */ public final class HjarSourceFileGenerator extends SourceFileGenerator { private final SourceFileGenerator delegate; private HjarSourceFileGenerator(SourceFileGenerator delegate) { super(delegate); this.delegate = delegate; } public static SourceFileGenerator wrap(SourceFileGenerator delegate) { return new HjarSourceFileGenerator<>(delegate); } @Override public Element originatingElement(T input) { return delegate.originatingElement(input); } @Override public ImmutableList topLevelTypes(T input) { return delegate.topLevelTypes(input).stream() .map(completeType -> skeletonType(completeType.build())) .collect(toImmutableList()); } private TypeSpec.Builder skeletonType(TypeSpec completeType) { TypeSpec.Builder skeleton = classBuilder(completeType.name) .addSuperinterfaces(completeType.superinterfaces) .addTypeVariables(completeType.typeVariables) .addModifiers(completeType.modifiers.toArray(new Modifier[0])) .addAnnotations(completeType.annotations); if (!completeType.superclass.equals(ClassName.OBJECT)) { skeleton.superclass(completeType.superclass); } completeType.methodSpecs.stream() .filter(method -> !method.modifiers.contains(PRIVATE) || method.isConstructor()) .map(this::skeletonMethod) .forEach(skeleton::addMethod); completeType.fieldSpecs.stream() .filter(field -> !field.modifiers.contains(PRIVATE)) .map(this::skeletonField) .forEach(skeleton::addField); completeType.typeSpecs.stream() .map(type -> skeletonType(type).build()) .forEach(skeleton::addType); return skeleton; } private MethodSpec skeletonMethod(MethodSpec completeMethod) { MethodSpec.Builder skeleton = completeMethod.isConstructor() ? constructorBuilder() : methodBuilder(completeMethod.name).returns(completeMethod.returnType); if (completeMethod.isConstructor()) { // Code in Turbine must (for technical reasons in javac) have a valid super() call for // constructors, otherwise javac will bark, and Turbine has no way to avoid this. So we retain // constructor method bodies if they do exist skeleton.addCode(completeMethod.code); } return skeleton .addModifiers(completeMethod.modifiers) .addTypeVariables(completeMethod.typeVariables) .addParameters(completeMethod.parameters) .addExceptions(completeMethod.exceptions) .varargs(completeMethod.varargs) .addAnnotations(completeMethod.annotations) .build(); } private FieldSpec skeletonField(FieldSpec completeField) { return FieldSpec.builder( completeField.type, completeField.name, completeField.modifiers.toArray(new Modifier[0])) .addAnnotations(completeField.annotations) .build(); } }