simple protobuf compilation with gradle

vach picture vach · Sep 28, 2015 · Viewed 28.2k times · Source

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...

Answer

TobiSH picture TobiSH · Sep 28, 2015

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.