Search code examples
javaamazon-web-servicesgradleaws-lambdadynamo-local

AWS Dev env setup with Gradle


I am setting up a convenience script for developers to be able to quickly get up and running without having to start several terminal sessions, boot DynamoDB, create a table, and then start the SAM Local API to mock out requests. I've decided to do this with Gradle, in part because I want to better learn Gradle, but also because it provides a simple wrapper to be included in the repo, customizable tasks, and Java dependency management.

So the steps I've identified are:

  1. grab the DynamoDB local jar
  2. start it
  3. create tables
  4. start the AWS Sam Local API

I've run into an issue with the jar main class not being able to find the dependency libraries. Here is the build gradle

SO's code formatting is unusable

As you can see, I place the binary in a build directory so it can be cleaned as needed by Gradle, which also contains the required libraries alongside the DynamoDbLocal-1.10.57.jar, like so:

SO's code formatting is the worst

And below is the terminal stacktrace of the Gradle task

enter image description here

So its unable to find the org/apache/commons/cli/ParseException class within the main runner of the jar. I had to use JDGui to open the manifest and locate what the runner class was so I could also be incorrect in that?

apply plugin: 'java'

repositories {
    mavenCentral()
    maven {
        url 'http://dynamodb-local.s3-website-us-west-2.amazonaws.com/release'
    }
}

def _LIBS = "$buildDir/libs"

defaultTasks 'run'

task copyToLib(type: Copy) {
    doFirst {
        println "Copying libs"
    }
    into _LIBS
    from configurations.runtime
    doLast {
        println "copy complete"
    }
}

task runDynamoDB(dependsOn: copyToLib, type: JavaExec) {
    doFirst {
        println "Starting DynamoDB local..."
    }
    systemProperty "java.library.path", _LIBS
    classpath sourceSets.main.runtimeClasspath
    main = 'com.amazonaws.services.dynamodbv2.local.main.ServerRunner'
    args "-inMemory", "-sharedDb"
    doLast {
        println "DynamoDB started"
    }
}

task createTables(dependsOn: runDynamoDB) {
    //aws dynamodb create-table --cli-input-json file://table_config.json --endpoint-url http://localhost:8000
}

task runSamLocalApi(dependsOn: runDynamoDB) {
    doFirst {
        println "Starting Sam Local API..."
    }
    doLast {
        println "Sam Local API started"
    }
}

task run(dependsOn: runSamLocalApi) {
    doFirst {
        println "Starting..."
    }
    doLast {
        println "Complete"
    }
}

dependencies {
    compile 'com.amazonaws:DynamoDBLocal:1.10.+'
    compile fileTree(dir: _LIBS, include: ['*.jar'])
    runtime files(_LIBS + '/DynamoDBLocal-1.10.57.jar')
}

Solution

  • The = operator invokes the set<Field> method in Groovy. This is the reason why the classpath of the runDynamoDB task only contains a single file. You should use the classpath(Object... paths) which appends to the classpath:

    Change the line to the following example to add the file to the default classpath:

    classpath files(...) // without =
    

    It's the same principle as for the systemProperty entry, which also appends to the previous collection of system properties.


    Please note, that your build script violates a lot of Gradle conventions and contains some problems, which may cause errors in the future:

    • Your println statements won't be executed when the respective tasks run, but when they are configured (regardless whether the task will run or not). You need to use doFirst and doLast closures.
    • You should add your local file dependencies to your build script (in the dependencies section) and use a Gradle configuration to build your classpath instead of collecting the files and their paths on your own.