28

If you're looking for sample gradle protobuf project look here.

I'm having hard time with gradle and protobuf, i want to create a simple gradle project that will take any proto files from default src/main/proto, src/test/proto and compile them to src/main/java, src/test/java accordingly, then pack that into a jar and publish to local repo.

Unfortunately i'm new to gradle and cant figure out how the original project is composed.

Here is my unfinished build.gradle file

apply plugin: 'java'
apply plugin: "com.google.protobuf"

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.7.0'
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.protobuf:protobuf-java:3.0.0-beta-1'
}

sourceSets {
    main {
        proto {
            srcDir 'src/main/proto'
        }
        java {
            srcDir 'src/main/java'
        }
    }
    test {
        proto {
            srcDir 'src/test/proto'
        }
        proto {
            srcDir 'src/test/java'
        }
    }
}

protobuf {
    // Configure the protoc executable
    protoc {
        // Download from repositories
        artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
    }
    generateProtoTasks {
        // all() returns the collection of all protoc tasks
        all().each { task ->
            // Here you can configure the task
        }

        // In addition to all(), you may get the task collection by various
        // criteria:

        // (Java only) returns tasks for a sourceSet
        ofSourceSet('main')

    }
}

After runing jar task we have this :

enter image description here

as you can see gradle builds both test and main protos to the same classes directory (red arrows), in the jar i can see both generated classes included (while tests should be skipped).

but the main problem is that I want to make compile proto files directly to appropriate source directories (blue arrows), after that ordinary build will do the correct thing... After all we need those classes in src to use them in business logic...

So we only need one task that compiles proto to appropriate src directory... nothing more.

src/main/proto to src/main/java
src/test/proto to src/test/java

The current project as it is is located here. Please help to configure this, i'm pretty sure lot of people will need it later...

rost0031
  • 1,894
  • 12
  • 21
vach
  • 10,571
  • 12
  • 68
  • 106
  • Could you please share w runnable example? I know it will be unfinished. – Opal Sep 28 '15 at 10:26
  • @Opal https://github.com/vach/sample-gradle-protobuf i'll leave the final working version there for others to use – vach Sep 28 '15 at 10:35
  • You might have a look into this example https://github.com/google/protobuf-gradle-plugin/blob/master/testProject/build.gradle – SubOptimal Sep 28 '15 at 11:46
  • @SubOptimal I did, it is a multiproject build, to make it work one needs to understand how the whole thing works, just try to import it and you'll see, it wont even work by itself, you shall fix some unresolved dependencies before you even will be able to create a project... I only want a simple minimalistic project... If you did that please just create one that works i'll understand the code as soon as i see it. – vach Sep 28 '15 at 12:12
  • 1
    @vach, have a look at this line: https://github.com/google/protobuf-gradle-plugin/blob/master/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy#L86. Since proto tasks are added in `afterEvaluate` you won't see this tasks in `gradle tasks` output - but they do exist. Run `gradlew generateProto` and investigate `build` dir. The sources get generated. – Opal Sep 28 '15 at 12:39
  • @Opal thanks to you i'm making some progress, i've updated the question please check it out... – vach Sep 28 '15 at 14:36
  • Sure. Will have a look, but no sooner than in few hours. – Opal Sep 28 '15 at 14:40
  • @vach can you please share a sample project as i am facing error in adding com.google.protobuf plugin. – anbu selvan Feb 28 '17 at 15:06
  • @anbuselvan sorry havent seen your message, if you didnt solve it i'll make a sample... – vach Mar 08 '17 at 08:26
  • @anbuselvan usually that means you didnt define the repository so make sure that you have this - buildscript { repositories { maven { url 'https://plugins.gradle.org/m2/' } } } – vach Mar 08 '17 at 08:50
  • @vach can you please make a sample as it will be helpful and FYI i am not building this protocol compiling sample using maven repository. – anbu selvan Mar 19 '17 at 14:05
  • @anbuselvan github.com/vach/sample-protobuf-grpc – vach Mar 20 '17 at 08:12
  • Link to the sample project is dead and there appears to be no working build anywhere on the internet. – G_V Jul 09 '19 at 09:11

1 Answers1

27

If I don't misunderstand your question it's quite simple to solve. If you don't want to distinguish between your own and the generated sources you just have to add set the generatedFileBaseDir like this generateProtoTasks.generatedFilesBaseDir = 'src'

So the entire build file looks like:

// ...

protobuf {
// Configure the protoc executable
protoc {
    // Download from repositories
    artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
}

generateProtoTasks.generatedFilesBaseDir = 'src' // <- that line 

generateProtoTasks {
    // all() returns the collection of all protoc tasks
    all().each { task ->
        // Here you can configure the task
    }

Than your folder looks like:

  • src/main/java/com/vach/tryout/AddressBookProtos.java
  • src/main/java/com/vach/tryout/protobuf/Main.java

BUT: That might not be the best idea to mix generate with handcrafted source code. So my suggestion would be to generate the source code into an own directory like generatedSources and add this directory to the java sourceSet. The build file would look like this:

sourceSets {
    main {
        proto {
            srcDir 'src/main/proto'
        }
        java {
            // include self written and generated code
            srcDirs 'src/main/java', 'generated-sources/main/java'            
        }
    }
    // remove the test configuration - at least in your example you don't have a special test proto file
}

protobuf {
    // Configure the protoc executable
    protoc {
        // Download from repositories
        artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
    }

    generateProtoTasks.generatedFilesBaseDir = 'generated-sources'

    generateProtoTasks {
        // all() returns the collection of all protoc tasks
        all().each { task ->
            // Here you can configure the task
        }

        // In addition to all(), you may get the task collection by various
        // criteria:

        // (Java only) returns tasks for a sourceSet
        ofSourceSet('main')

    }   
}

Your directory will look like this

  • src/main/proto/dtos.proto
  • src/main/java/com/vach/tryout/protobuf/Main.java
  • generated-sources/main/java/com/vach/tryout/AddressBookProtos.java

A nice side effect is that you can ignore this generated-sources dir in your git configuration. That's always a good idea not to publish generated source code.

Joeri Hendrickx
  • 16,947
  • 4
  • 41
  • 53
TobiSH
  • 2,833
  • 3
  • 23
  • 33
  • I dont quite understand why its considered bad to have generated code near handcrafted that even default behaviour separates it to different directory... Afterall protobuf is a tool to generate DTOs that are efficiently serializing and deserializing themselfs... and you use them in your handcrafted code... if you separate them to different directory, you need to configure ides to know about aditional source directory... i dont really see good enough reason to do that... – vach Sep 28 '15 at 19:30
  • the way I intend to use protobuf is to have one small project that contains all the DTOs which is exposing dtos.jar to local repo and other projects use it... – vach Sep 28 '15 at 19:31
  • @vach Regarding to your first question - why do you seperated generated code from 'written code': That is in deed a matter of taste. You can find a discussion here: [http://stackoverflow.com/questions/893913/should-i-store-generated-code-in-source-control]. Beside having smaller commits some might accidentally change the generated code. Furtheremore removing types will get harder (you have to delete your proto file and the java file(s)). – TobiSH Sep 28 '15 at 21:07
  • So the way to do it is generate the code in some other directory (not included in vcs), but have it visible in local environment. Then any developer checking out a code will get updates trough proto files and build it himself? I hope i picture it right? I suppose this will also allow to immidiately detect any accidental handwritten change in generated code... – vach Sep 29 '15 at 07:02
  • thanks for answer that was exactly what i was looking for, however i agree with your point that generated code shall not be in vcs, unfortunately i'm somehow not configuring it properly. Please look at the question update... – vach Sep 29 '15 at 07:17
  • 1
    @vach I didn't got your problem - maybe you could update your github project (or just take my pull-request) – TobiSH Sep 29 '15 at 09:31
  • @vach @TobiSH So `Main.class` is where the `AddressBookProtos.java` is used? – r2_d2 Oct 20 '16 at 10:26
  • Not to comment on a 7 year old post but I just started with protobuf and Intellij will constantly mark your src directory as a "generated sources root" and pop up a banner that you could be editing generated files, if you don't store the generated code separately. – TheFunk Mar 26 '22 at 21:49