Skip to content

Commit

Permalink
Attempt #4 Adds FakeAutoCodecProcessor to bazel-distfile.
Browse files Browse the repository at this point in the history
Change-Id: Ie8dd0aa0ed6234fc3fd2e337fd50f9f7d5c7d2c1
PiperOrigin-RevId: 179607524
  • Loading branch information
aoeui authored and Copybara-Service committed Dec 20, 2017
1 parent caa9e08 commit 1a4f791
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 24 deletions.
2 changes: 2 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ genrule(
srcs = [
":bazel-srcs",
"//src:derived_java_srcs",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec:bootstrap_autocodec.tar",
],
outs = ["bazel-distfile.zip"],
cmd = "$(location :combine_distfiles) $@ $(SRCS)",
Expand All @@ -96,6 +97,7 @@ genrule(
srcs = [
":bazel-srcs",
"//src:derived_java_srcs",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec:bootstrap_autocodec.tar",
],
outs = ["bazel-distfile.tar"],
cmd = "$(location :combine_distfiles_to_tar.sh) $@ $(SRCS)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package com.google.devtools.build.lib.skyframe.serialization.autocodec;

import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
Expand Down Expand Up @@ -55,10 +54,6 @@
*/
@AutoService(Processor.class)
public class AutoCodecProcessor extends AbstractProcessor {
// Synthesized classes will be prefixed with AutoCodec_.
public static final String GENERATED_CLASS_NAME_PREFIX = "AutoCodec";
private static final Class<AutoCodec> ANNOTATION = AutoCodec.class;

/**
* Passing {@code --javacopt=-Aautocodec_print_generated} to {@code blaze build} tells AutoCodec
* to print the generated code.
Expand All @@ -74,7 +69,7 @@ public Set<String> getSupportedOptions() {

@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of(ANNOTATION.getCanonicalName());
return ImmutableSet.of(AutoCodecUtil.ANNOTATION.getCanonicalName());
}

@Override
Expand All @@ -90,8 +85,8 @@ public synchronized void init(ProcessingEnvironment processingEnv) {

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(ANNOTATION)) {
AutoCodec annotation = element.getAnnotation(ANNOTATION);
for (Element element : roundEnv.getElementsAnnotatedWith(AutoCodecUtil.ANNOTATION)) {
AutoCodec annotation = element.getAnnotation(AutoCodecUtil.ANNOTATION);
switch (annotation.strategy()) {
case CONSTRUCTOR:
buildCodecUsingConstructor((TypeElement) element);
Expand Down Expand Up @@ -120,7 +115,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
*/
private void buildCodecUsingConstructor(TypeElement classElement) {
TypeSpec.Builder codecClassBuilder =
TypeSpec.classBuilder(getCodecName(classElement))
TypeSpec.classBuilder(AutoCodecUtil.getCodecName(classElement))
.superclass(TypeName.get(classElement.asType()));

TypeElement encodedType = getEncodedType(classElement);
Expand Down Expand Up @@ -166,21 +161,6 @@ private static String paramNameAsAccessor(String name) {
return "get" + name.substring(0, 1).toUpperCase() + name.substring(1) + "()";
}

/**
* Name of the generated codec class.
*
* <p>For {@code Foo.Bar.Codec} this is {@code AutoCodec_Foo_Bar_Codec}.
*/
private static String getCodecName(Element element) {
ImmutableList.Builder<String> classNamesBuilder = new ImmutableList.Builder<>();
do {
classNamesBuilder.add(element.getSimpleName().toString());
element = element.getEnclosingElement();
} while (element instanceof TypeElement);
classNamesBuilder.add(GENERATED_CLASS_NAME_PREFIX);
return classNamesBuilder.build().reverse().stream().collect(Collectors.joining("_"));
}

private void addSerializeMethodUsingConstructor(
TypeSpec.Builder codecClassBuilder,
TypeElement encodedType,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// 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 com.google.devtools.build.lib.skyframe.serialization.autocodec;

import com.google.common.collect.ImmutableList;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

/** Static utilities for AutoCodec processors. */
class AutoCodecUtil {
// Synthesized classes will have `_AutoCodec` suffix added.
public static final String GENERATED_CLASS_NAME_SUFFIX = "AutoCodec";
static final Class<AutoCodec> ANNOTATION = AutoCodec.class;

/**
* Name of the generated codec class.
*
* <p>For {@code Foo.Bar} this is {@code Foo_Bar_AutoCodec}.
*/
static String getCodecName(Element element) {
ImmutableList.Builder<String> classNamesBuilder = new ImmutableList.Builder<>();
classNamesBuilder.add(GENERATED_CLASS_NAME_SUFFIX);
do {
classNamesBuilder.add(element.getSimpleName().toString());
element = element.getEnclosingElement();
} while (element instanceof TypeElement);
return classNamesBuilder.build().reverse().stream().collect(Collectors.joining("_"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,52 @@ java_library(
srcs = ["AutoCodecProcessor.java"],
deps = [
":autocodec-annotation",
":autocodec-util",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization",
"//third_party:auto_service",
"//third_party:guava",
"//third_party/java/javapoet",
"//third_party/protobuf:protobuf_java",
],
)

# Code shared between autocodec-processor and fake-autocodec-processor.
java_library(
name = "autocodec-util",
srcs = ["AutoCodecUtil.java"],
deps = [
":autocodec-annotation",
"//third_party:guava",
],
)

# This is a fake implementation for bootstrapping. It must *not* be used in production.
java_library(
name = "fake-autocodec-processor",
srcs = ["FakeAutoCodecProcessor.java"],
deps = [
":autocodec-util",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization",
"//third_party:auto_service",
"//third_party:guava",
"//third_party/java/javapoet",
"//third_party/protobuf:protobuf_java",
],
)

load("//tools/build_defs/pkg:pkg.bzl", "pkg_tar")

# .tar archive of dependencies used for bootstrapping.
pkg_tar(
name = "bootstrap_autocodec",
# The .jar files are created within the .tar file under third_party/bazel_bootstrap so that
# they will appear there in bazel-distfile, which in turn makes them visible for bootstrapping
# from the LIBRARY_JARS rule of bazel/scripts/bootstrap/compile.sh.
files = {
":libautocodec-annotation.jar": "third_party/bazel_bootstrap/libautocodec-annotation.jar",
":libautocodec-util.jar": "third_party/bazel_bootstrap/libautocodec-util.jar",
":libfake-autocodec-processor.jar": "third_party/bazel_bootstrap/libfake-autocodec-processor.jar",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization:libserialization.jar": "third_party/bazel_bootstrap/libserialization.jar",
},
visibility = ["//visibility:public"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// 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 com.google.devtools.build.lib.skyframe.serialization.autocodec;

import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;

/**
* A fake annotation processor for bootstrapping.
*
* <p>When bootstrapping, annotation processors inside the Bazel source tree are not available which
* means that if there are dependencies on generated code, bootstrapping will fail. This processor
* generates stub code to pass the initial boostrapping phase.
*/
@AutoService(Processor.class)
public class FakeAutoCodecProcessor extends AbstractProcessor {
private ProcessingEnvironment env; // Captured from `init` method.

@Override
public Set<String> getSupportedAnnotationTypes() {
return ImmutableSet.of(AutoCodecUtil.ANNOTATION.getCanonicalName());
}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported(); // Supports all versions of Java.
}

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.env = processingEnv;
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(AutoCodecUtil.ANNOTATION)) {
TypeElement encodedType = (TypeElement) element;
TypeSpec.Builder codecClassBuilder =
TypeSpec.classBuilder(AutoCodecUtil.getCodecName(encodedType))
.addSuperinterface(
ParameterizedTypeName.get(
ClassName.get(ObjectCodec.class), TypeName.get(encodedType.asType())));
codecClassBuilder.addMethod(
MethodSpec.methodBuilder("getEncodedClass")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(
ParameterizedTypeName.get(
ClassName.get(Class.class), TypeName.get(encodedType.asType())))
.addStatement("throw new RuntimeException(\"Shouldn't be called.\")")
.build());
codecClassBuilder.addMethod(
MethodSpec.methodBuilder("serialize")
.addModifiers(Modifier.PUBLIC)
.addParameter(TypeName.get(encodedType.asType()), "input")
.addParameter(CodedOutputStream.class, "codedOut")
.addAnnotation(Override.class)
.addStatement("throw new RuntimeException(\"Shouldn't be called.\")")
.build());
codecClassBuilder.addMethod(
MethodSpec.methodBuilder("deserialize")
.addModifiers(Modifier.PUBLIC)
.returns(TypeName.get(encodedType.asType()))
.addParameter(CodedInputStream.class, "codedIn")
.addAnnotation(Override.class)
.addStatement("throw new RuntimeException(\"Shouldn't be called.\")")
.build());
String packageName =
env.getElementUtils().getPackageOf(encodedType).getQualifiedName().toString();
try {
JavaFile file = JavaFile.builder(packageName, codecClassBuilder.build()).build();
file.writeTo(env.getFiler());
} catch (IOException e) {
env.getMessager()
.printMessage(
Diagnostic.Kind.ERROR, "Failed to generate output file: " + e.getMessage());
}
}
return true;
}
}

0 comments on commit 1a4f791

Please sign in to comment.