Skip to content

Commit dd4abae

Browse files
committed
core: Rewrite builder class signatures to avoid internal class
This provides us a path forward with grpc#7211 (hiding AbstractManagedChannelImplBuilder and AbstractServerImplBuilder) while providing users a migration path to manage the ABI breakage (grpc#7552). We do a .class hack so that recompiling avoids the internal class reference yet the old methods are still available. Leaving the classes as-is causes javac to compile two versions of each method, one returning the public class (e.g. ServerBuilder) and one returning the internal class (e.g., AbstractServerImplBuilder). However, we rewrite the signature that is used at compile time so that new compilations will not reference internal-returning methods. This is intended to be temporary, just to give a migration path. Once we have given users some time to recompile we will remove this rewriting and change the generics to use public classes.
1 parent 43d2e53 commit dd4abae

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

core/build.gradle

+50
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
buildscript {
2+
dependencies {
3+
classpath 'com.google.guava:guava:30.0-android'
4+
}
5+
}
6+
17
plugins {
28
id "java-library"
39
id "maven-publish"
@@ -7,6 +13,10 @@ plugins {
713
id "ru.vyarus.animalsniffer"
814
}
915

16+
import static java.nio.charset.StandardCharsets.US_ASCII;
17+
18+
import com.google.common.primitives.Bytes;
19+
1020
description = 'gRPC: Core'
1121

1222
evaluationDependsOn(project(':grpc-context').path)
@@ -53,7 +63,47 @@ animalsniffer {
5363

5464
import net.ltgt.gradle.errorprone.CheckSeverity
5565

66+
def replaceBytes(byte[] haystack, byte[] needle, byte[] replacement) {
67+
int i = Bytes.indexOf(haystack, needle);
68+
assert i != -1;
69+
byte[] result = new byte[haystack.length - needle.length + replacement.length];
70+
System.arraycopy(haystack, 0, result, 0, i);
71+
System.arraycopy(replacement, 0, result, i, replacement.length);
72+
System.arraycopy(haystack, i + needle.length, result, i + replacement.length, haystack.length - i - needle.length);
73+
return result;
74+
}
75+
76+
def bigEndian(int value) {
77+
return [value >> 8, value & 0xFF] as byte[];
78+
}
79+
80+
def replaceConstant(File file, String needle, String replacement) {
81+
// CONSTANT_Utf8_info. https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.7
82+
byte[] needleBytes = Bytes.concat(
83+
[1] as byte[], bigEndian(needle.length()), needle.getBytes(US_ASCII));
84+
byte[] replacementBytes = Bytes.concat(
85+
[1] as byte[], bigEndian(replacement.length()), replacement.getBytes(US_ASCII));
86+
file.setBytes(replaceBytes(file.getBytes(), needleBytes, replacementBytes));
87+
}
88+
5689
plugins.withId("java") {
90+
compileJava {
91+
doLast {
92+
// Replace value of Signature Attribute.
93+
// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.9
94+
project.replaceConstant(
95+
destinationDirectory.file(
96+
"io/grpc/internal/AbstractManagedChannelImplBuilder.class").get().getAsFile(),
97+
"<T:Lio/grpc/internal/AbstractManagedChannelImplBuilder<TT;>;>Lio/grpc/ManagedChannelBuilder<TT;>;",
98+
"<T:Lio/grpc/ManagedChannelBuilder<TT;>;>Lio/grpc/ManagedChannelBuilder<TT;>;");
99+
project.replaceConstant(
100+
destinationDirectory.file(
101+
"io/grpc/internal/AbstractServerImplBuilder.class").get().getAsFile(),
102+
"<T:Lio/grpc/internal/AbstractServerImplBuilder<TT;>;>Lio/grpc/ServerBuilder<TT;>;",
103+
"<T:Lio/grpc/ServerBuilder<TT;>;>Lio/grpc/ServerBuilder<TT;>;");
104+
}
105+
}
106+
57107
compileJmhJava {
58108
// This project targets Java 7 (no method references)
59109
options.errorprone.check("UnnecessaryAnonymousClass", CheckSeverity.OFF)

0 commit comments

Comments
 (0)