Kylar
Kylar

Reputation: 9324

How do I Import a .proto file from a dependency jar using gradle

I have a project that creates a set of protobuf objects and GRPC stubs.

I have a dependency on a jar with other .proto files in it, that I would like to use in my project.

ie:

project-abc-0.0.1.jar contains a file: /some-types.proto It contains these pieces:

package foo_companyname;
message StatusItem {
    string status = 1;
    string statusDescription = 2;
}

my project has a build.gradle file where I am trying to import it like so:

buildscript {
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
    }
}

dependencies {
    compile(group: 'com.companyname', name: 'project-abc', version: '0.0.1')
}

Then, inside my new "enhanced-status.proto" I'm doing this:

import "foo_companyname/some-types.proto";

message EnhancedStatus{
    string author = 1;
    repeated StatusItem status = 2;
}

If I don't reference the other .proto, everything works fine - I'm able to generate all the correct java any python classes. As soon as I add it, I'm getting this:

Execution failed for task ':generateProto'.
> protoc: stdout: . stderr: foo_companyname/some-types.proto: File not found.
  enhanced-status.proto: Import "foo_companyname/some-types.proto" was not found or had errors.
  enhanced-status.proto:26:19: "StatusItem" is not defined.

I'm assuming there's some trick to getting gradle or protoc to find .proto sources that are in a jar file? Or do I need to extract the jar file's .proto into my own /proto dir? That would cause a conflict, since the jar has a compiled version of some-types.proto already, and I don't want to compile it again.

Upvotes: 14

Views: 13199

Answers (6)

maximus
maximus

Reputation: 1548

It is pointed out that the Protobuf Plugin for Gradle would do the job, but I still can't understand how to specify the path of the dependency proto file in my own proto file. I figured it out through trial and error, and here it is:

First, use Protobuf Plugin for Gradle and add the library jar that contains proto files as implementation dependency:

plugins {
    id "com.google.protobuf" version "0.8.17"
    id "java"
    id "maven-publish"
}

dependencies {
    implementation "com.google.protobuf:protobuf-java:3.12.2"
    implementation "io.grpc:grpc-all:1.49.1"
    implementation "javax.annotation:javax.annotation-api:1.3.2"
    implementation "my.company:common-schema:1.0.14"  // <-- this is my library
}

Next, try to build the project by running assemble or build task. Then have a look at the build folder generated by the build, you will find an extracted-include-protos folder that contains the proto files from the library. In my IntelliJ window it looks like this:

enter image description here

Include any proto file into your proto file using the path from above folder structure. To use a type from imported proto, use its fully qualified type name, like this:

syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
import "grpc/currency/Currency.proto";  <-- proto file from library
import "grpc/country/Country.proto";    <-- proto file from library

package com.mycompany.myservice;

message MyMessage {
  ...
  com.mycompany.common.currency.CurrencyCode currency = 11;
  ...
}

Finally, run another build and your proto files should get compiled successfully.

P.S. I don't know why the main folder in the above structure is disregarded, so you may have to try several times to find out what is working. Another minor thing: IntelliJ still highlights the import statements in red (can't resolve the file), but the build is successful and that's good enough :)

Upvotes: 2

Elena Spb
Elena Spb

Reputation: 1

I faced with the same case and no one here answers works for me. that actions helps me:

  1. add include("build/extracted-include-protos/main/data/*.proto")
dependencies {
    implementation("com.google.protobuf:protobuf-java:3.8.0")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
    implementation("io.grpc:grpc-kotlin-stub:1.1.0")
    implementation("io.grpc:grpc-protobuf:1.38.0")
    implementation("my-external-lib-with-compiled-proto-jar") //!!!!
}

protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.17.2"
    }
    plugins {
        id("grpc") {
            artifact = "io.grpc:protoc-gen-grpc-java:1.38.0"
        }
        id("grpckt") {
            artifact = "io.grpc:protoc-gen-grpc-kotlin:1.1.0:jdk7@jar"
        }
        generateProtoTasks {
            all().forEach {
                it.plugins {
                    id("grpc")
                    id("grpckt")
                }
            }
        }
    }
}

sourceSets {
    main {
        proto {
            srcDirs("src/main/proto")
            include("build/extracted-include-protos/main/data/*.proto")//!!!
        }
        java {
            java.srcDir("build/generated/source/proto/main/java")
            java.srcDir("build/generated/source/proto/main/grpc")
            java.srcDir("build/generated/source/proto/main/grpckt")
        }
      }
   }
  1. to make external proto green in current proto we can add in Idea settings Languages/Protobuf/.. path to your YOUR_PATH/lib/build/extracted-include-protos/main, fox example: enter image description here

Upvotes: 0

umop apisdn
umop apisdn

Reputation: 683

Here's the solution that worked for me:

  1. Add the JAR as a dependency (as you have done)
buildscript {
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
    }
}

dependencies {
    compile(group: 'com.companyname', name: 'project-abc', version: '0.0.1')
}
  1. Import the proto file directly without the package name (see what @Lukas mentioned)
import "some-types.proto";
  1. Reference the model in the imported proto file with the package name
message EnhancedStatus {
    string author = 1;
    repeated foo_companyname.StatusItem status = 2;
}

Upvotes: 1

scottsue
scottsue

Reputation: 128

Using the google protobuf gradle plugin

plugins {
   id 'com.google.protobuf' version "0.8.5"
}

You should just need to specify your dependent jar in the dependencies block (i.e, as a 'protobuf' dependency, not 'compile'):

dependencies {           
    protobuf "com.companyname:project-abc:0.0.1"
}

Upvotes: 10

Enrico La Sala
Enrico La Sala

Reputation: 86

You need to add the package name foo_companyname for using StatusItem message, try in this way:

import "foo_companyname/some-types.proto";

message EnhancedStatus{
    string author = 1;
    repeated foo_companyname.StatusItem status = 2;
}

Upvotes: 3

Lukas K&#246;rfer
Lukas K&#246;rfer

Reputation: 14493

The Protobuf Plugin for Gradle supports protobuf files in dependencies:

If a compile configuration has a dependency on a project or library jar that contains proto files, they will be added to the --proto_path flag of the protoc command line, so that they can be imported in the proto files of the dependent project. The imported proto files will not be compiled since they have already been compiled in their own projects.

Upvotes: 3

Related Questions