Hi Team,
I am seeking help for an issue pretty similar to this one: Cannot access compiled protobuf java class from one project in src/test of another project.
Since code says more than a thousand words, I prepared the public repository multi-project to discuss details.
Actually, I am struggeling a bit to distinguish between a plain multi-project-approach and really share outputs between projects. I am not fully sure, if my generated code counts as “(sub-) project”, since there is no main class or similar, just generated java code which is used elsewhere and shall not repeatedly compiled.
But first things first.
Composite Build
The branch composite-build shows a producer and consumer (sub-) project (package?), where producer generates the java code from a sample proto file and the consumer tries to use it in FooService.java. When compiling the consumer, I receive
$ ./gradlew :consumer:build -Duser.language=en
> Task :consumer:compileJava FAILED
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:17: error: cannot access GeneratedFile
var request = Foo.FooRequest.newBuilder().setBar("Raise the Bar!").build();
^
class file for com.google.protobuf.GeneratedFile not found
1 error
[Incubating] Problems report is available at: file:///***/multi-project/build/reports/problems/problems-report.html
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':consumer:compileJava'.
> Compilation failed; see the compiler output below.
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:17: error: cannot access GeneratedFile
var request = Foo.FooRequest.newBuilder().setBar("Raise the Bar!").build();
^
class file for com.google.protobuf.GeneratedFile not found
1 error
* Try:
> Check your code and dependencies to fix the compilation error(s)
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
BUILD FAILED in 1s
8 actionable tasks: 1 executed, 7 up-to-date
Shared Artifacts
This is similar to the issue in the linked ticket above, i.e., I try to follow the share outputs between projects on branch shared-artifacts. When trying to build the consumer, it seems even worse. Maybe my settings.gradle.kts is not setup properly?
$ ./gradlew :consumer:build -Duser.language=en
> Task :consumer:compileJava FAILED
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:3: error: package foo does not exist
import foo.Foo;
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:4: error: package foo does not exist
import foo.FooServiceGrpc;
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:10: error: package FooServiceGrpc does not exist
private final FooServiceGrpc.FooServiceBlockingStub blockingStub;
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:12: error: package FooServiceGrpc does not exist
public FooService(FooServiceGrpc.FooServiceBlockingStub blockingStub) {
^
***\multi-project\consumer\src\main\java\consumer\grpc\GrpcClientFactory.java:3: error: package foo does not exist
import foo.FooServiceGrpc;
^
***\multi-project\consumer\src\main\java\consumer\grpc\GrpcClientFactory.java:12: error: package FooServiceGrpc does not exist
public FooServiceGrpc.FooServiceBlockingStub fooServiceBlockingStub(GrpcChannelFactory factory){
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:17: error: package Foo does not exist
var request = Foo.FooRequest.newBuilder().setBar("Raise the Bar!").build();
^
***\multi-project\consumer\src\main\java\consumer\grpc\GrpcClientFactory.java:13: error: cannot find symbol
return FooServiceGrpc.newBlockingStub(factory.createChannel("foo"));
^
symbol: variable FooServiceGrpc
location: class GrpcClientFactory
8 errors
[Incubating] Problems report is available at: file:///***/multi-project/build/reports/problems/problems-report.html
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':consumer:compileJava'.
> Compilation failed; see the compiler output below.
***\multi-project\consumer\src\main\java\consumer\grpc\GrpcClientFactory.java:13: error: cannot find symbol
return FooServiceGrpc.newBlockingStub(factory.createChannel("foo"));
^
symbol: variable FooServiceGrpc
location: class GrpcClientFactory
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:3: error: package foo does not exist
import foo.Foo;
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:4: error: package foo does not exist
import foo.FooServiceGrpc;
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:10: error: package FooServiceGrpc does not exist
private final FooServiceGrpc.FooServiceBlockingStub blockingStub;
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:12: error: package FooServiceGrpc does not exist
public FooService(FooServiceGrpc.FooServiceBlockingStub blockingStub) {
^
***\multi-project\consumer\src\main\java\consumer\grpc\GrpcClientFactory.java:3: error: package foo does not exist
import foo.FooServiceGrpc;
^
***\multi-project\consumer\src\main\java\consumer\grpc\GrpcClientFactory.java:12: error: package FooServiceGrpc does not exist
public FooServiceGrpc.FooServiceBlockingStub fooServiceBlockingStub(GrpcChannelFactory factory){
^
***\multi-project\consumer\src\main\java\consumer\foo\FooService.java:17: error: package Foo does not exist
var request = Foo.FooRequest.newBuilder().setBar("Raise the Bar!").build();
^
8 errors
* Try:
> Check your code and dependencies to fix the compilation error(s)
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
BUILD FAILED in 1s
1 actionable task: 1 executed
Custom Compile Task aka Incremental Build
Last but not least, I fully agree with this comment: Shouldn’t it be possible to simply add a custom task which compiles only the generated code? To my understanding, gradle requires for a custom task means to decide if the task is “UP-TO-DATE”, i.e., if the input and output is still the same?
For that approach, I aggregated all code in a single src/main folder-structure on the branch task. I tried to get support for this approach on Stackoverflow: Gradle Incremental Build Generated gRPC Java Code, but probably the question there is too generic without more precise context.
Summarized, how to make sure only parts of the code are re-compiled which have been changed. Any help is appreciated. Please, feel free to ask for details if I did not explain something detailed enough.
Regards, pd