plugins { id 'java' id 'application' id 'maven-publish' id 'com.palantir.git-version' version '2.0.0' id 'com.gradleup.shadow' version '9.0.1' } group = 'com.conveyal' // set version to `git describe --tags --always --first-parent`, plus '.dirty' if local changes are present. version gitVersion() java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } withSourcesJar() } jar { // For Java 11+ Modules, specify a module name. // Do not create module-info.java until all our dependencies specify a module name. // Main-Class BackendMain will start a local backend. // Build-Jdk-Spec mimics a Maven manifest entry that helps us automatically install or select the right JVM. // Implementation-X attributes are needed for ImageIO (used by Geotools) to initialize in some environments. manifest { attributes 'Automatic-Module-Name': 'com.conveyal.r5', 'Main-Class': 'com.conveyal.analysis.BackendMain', 'Build-Jdk-Spec': java.toolchain.languageVersion, 'Implementation-Title': 'Conveyal Analysis Backend', 'Implementation-Vendor': 'Conveyal LLC', 'Implementation-Version': project.version } } shadowJar { filesMatching("META-INF/services/**") { duplicatesStrategy = DuplicatesStrategy.INCLUDE } mergeServiceFiles() } // Allow reflective access by ObjectDiffer to normally closed Java internals. Used for round-trip testing serialization. // IntelliJ seems not to pass these JVM arguments when running tests from within the IDE, so the Kryo serialization // tests may only succeed under command line Gradle. test { useJUnitPlatform() jvmArgs = ['--add-opens=java.base/java.io=ALL-UNNAMED', '--add-opens=java.base/java.time=ALL-UNNAMED', '--add-opens=java.base/java.time.zone=ALL-UNNAMED', '--add-opens=java.base/java.lang=ALL-UNNAMED'] } // Set up publication of jar files to GitHub Packages Maven repository. // On GitHub Actions, GITHUB_ACTOR env variable is supplied without specifying it in action yml. publishing { repositories { maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/conveyal/r5") credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") } } } publications { // The shadow plugin automatically creates and registers a component called "shadow" for integration with this // Maven publish plugin. `gradle publish` will then upload both shadow jar and simple jar to Github Packages. // See https://imperceptiblethoughts.com/shadow/getting-started/#default-java-groovy-tasks // To run R5 with dependencies, Conveyal does not use shadow jars anymore, only the zip distribution or runBackend. // For development builds and tests we don't need to produce a shadow jar, only publish the much smaller plain // jar without dependencies to Github Packages. For now, we continue to attach shadow jars to tagged releases. gpr(MavenPublication) { from(components.java) } } } tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } // A task to put all dependency JARs needed at runtime into a single directory. This is a Sync // rather than a Copy, to prevent accumulation of different JAR versions in the directory. If // multiple versions are accidentally deployed together, the JVM will load a version based only on // classpath enumeration order. task copyDependencies(type: Sync) { from(sourceSets.main.runtimeClasspath) { include '*.jar' } into 'dependencies' } application { applicationDefaultJvmArgs = ['-Xmx6G'] mainClass = 'com.conveyal.analysis.BackendMain' } // Run R5 as a local analysis backend with all dependencies on the classpath, without building a shadowJar. task runBackend (type: JavaExec) { dependsOn(build) maxHeapSize('7G') classpath(sourceSets.main.runtimeClasspath) mainClass = 'com.conveyal.analysis.BackendMain' } // Start up an analysis local backend and ask it to shut down immediately. // This is used to check in the automated build that the JAR is usable in end-to-end tests before we keep it. // Create a configuration properties file (by copying the template) before running this task. task testRunnable(type: JavaExec) { dependsOn(build) classpath(sourceSets.main.runtimeClasspath) mainClass = 'com.conveyal.analysis.BackendMain' jvmArgs("-Dconveyal.immediate.shutdown=true") } // Create a properties file so Java code can be aware of its own version. Properties allow exposing multiple values // such as the full commit ID and branch name, rather than just the version available in the JAR manifest. task createVersionProperties(dependsOn: processResources) { doLast { def details = versionDetails() def dir = new File(buildDir, "resources/main/com/conveyal/r5/") mkdir(dir) new File(dir, "version.properties").withWriter { w -> Properties p = new Properties() p['version'] = project.version.toString() p['commit'] = details.gitHashFull p['branch'] = details.branchName ?: "NONE" // avoid NPE when building pushed tag p.store w, null } // Also make a simple one-line version.txt for scripts to use new File(dir, "version.txt").text = "$version" } } // Fix inconsistent Gradle behavior (see https://github.com/gradle/gradle/issues/16791) // By default JavaExec tasks use the JVM Gradle was launched with, ignoring the project-level toolchain. tasks.withType(JavaExec).configureEach { javaLauncher.set(javaToolchains.launcherFor(java.toolchain)) } classes { dependsOn createVersionProperties } repositories { // Do not use mavenLocal() which is only for interoperability with Maven, let Gradle manage its own cache. // Put Open Source Geospatial before Maven Central to get JAI core, see https://stackoverflow.com/a/26993223 maven { url 'https://repo.osgeo.org/repository/release/' } mavenCentral() // Polyline encoder 0.2 is now in Maven repo maven { url 'https://maven.conveyal.com' } } // Exclude all JUnit 4 transitive dependencies - IntelliJ bug causes it to think we're using Junit 4 instead of 5. configurations.all { exclude group: "junit", module: "junit" } // Hold all com.fasterxml.jackson modules at one version, overriding requests from transitive dependencies. // Under Jackson 2.15 or newer, bson4jackson corrupts numbers buffered during polymorphic deserialization, // yielding empty strings or zeros. An AWS SDK upgrade triggered this problem. // The cap may be raised or removed only when mongojack and bson4jackson are removed. // This is not an enforcedPlatform because that would force versions on downstream projects and is disallowed. // The group prefix ends with a dot to cover all Jackson modules while excluding the jackson-bom platform itself. configurations.all { resolutionStrategy.eachDependency { details -> if (details.requested.group.startsWith('com.fasterxml.jackson.')) { details.useVersion(details.requested.name == 'jackson-databind' ? '2.10.5.1' : '2.10.5') details.because('bson4jackson and mongojack corrupt MongoDB reads under Jackson 2.15 or newer') } } } dependencies { // Provides our logging API implementation 'org.slf4j:slf4j-api:2.0.7' // Implementation of the logging API implementation 'ch.qos.logback:logback-classic:1.4.11' // Spark is an HTTP framework built on Jetty. Its name is the same as several other projects. implementation (group: 'com.sparkjava', name: 'spark-core', version: '2.7.2') { exclude group: 'org.slf4j', module: 'slf4j-simple' } // Database driver. implementation 'org.mongodb:mongodb-driver-legacy:5.2.0' // Legacy system for storing Java objects, this functionality is now provided by the MongoDB driver itself. implementation 'org.mongojack:mongojack:2.10.1' // JSON serialization and deserialization from and to Java objects. The BOM aligns all // com.fasterxml.jackson modules on one version but is published only as an advisory import. // The resolution rule above this dependencies block provides a hard cap on version numbers. implementation platform('com.fasterxml.jackson:jackson-bom:2.10.5.20201202') implementation 'com.fasterxml.jackson.core:jackson-core' implementation 'com.fasterxml.jackson.core:jackson-databind' // Parses CSV. GTFS is a set of zipped CSV files, and some of our other inputs are CSV files. implementation 'net.sourceforge.javacsv:javacsv:2.0' // Parses command line arguments (including standard switches) to main methods. implementation 'com.beust:jcommander:1.30' // GeoTools provides GIS functionality on top of JTS topology suite. def geotoolsVersion = '25.2' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-main' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-opengis' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-referencing' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-shapefile' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-coverage' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-geojsondatastore' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-geopkg' implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-geotiff' // Provides the EPSG coordinate reference system catalog as an HSQL database. implementation group: 'org.geotools', version: geotoolsVersion, name: 'gt-epsg-hsql' implementation 'com.wdtinc:mapbox-vector-tile:3.1.0' // Legacy JTS with com.vividsolutions package name. Newer Geotools compatible with Java 11 uses a newer version of // JTS with the org.locationtech package name. But our MapDB format includes serialized JTS geometries with the // old package name, and some bugs in the older gtfs-lib that produced those MapDB files are preventing us from // migrating to a newer format. So we import both JTS packages and convert between them. implementation 'com.vividsolutions:jts:1.13' // Pure Java database backend providing disk-backed storage that looks like a Java map. 1.0.8 was the second to // last release of 1.x, and use of 2.x was not recommended. We should not bump this unless migrating to 3.x or 4.x. // See changelog at http://www.mapdb.org/changelog/ implementation 'org.mapdb:mapdb:1.0.8' implementation 'commons-fileupload:commons-fileupload:1.3.1' implementation 'commons-codec:commons-codec:1.4' // Commons IO gives us BOMInputStream for handling UTF-8 Byte Order Marks. implementation 'commons-io:commons-io:2.6' // Java 8 rewrite of the Guava cache with asynchronous LoadingCaches. We don't currently use the async // capabilities, but Caffeine's LoadingCache syntax is more modern idiomatic Java than Guava's. implementation 'com.github.ben-manes.caffeine:caffeine:2.8.1' implementation ('org.apache.httpcomponents:httpclient:4.5.13') { because 'Force use of version used by AWS SDK instead of other versions used by our transitive dependencies.' // TODO eventually migrate over to Java's built-in HTTP client. } // Persistent storage of files / objects on Amazon S3. // Now used only for Seamless Census TODO eliminate this final AWS dependency implementation 'com.amazonaws:aws-java-sdk-s3:1.12.797' // Commons Math gives us FastMath, MersenneTwister, and low-discrepancy vector generators. implementation 'org.apache.commons:commons-math3:3.0' // Provides some Kryo serializers for Guava and Trove collecitons. // Also provides classes for testing that a round trip through serialization reproduces the same network. // This is an external dependency (not merged into backend) because it's also used by OTP2. implementation 'com.conveyal:kryo-tools:1.6.0' // Ensure the versions of the next three dependencies match the transitive dependencies of kryo-tools. implementation 'com.esotericsoftware:kryo:5.5.0' // Guava provides a lot of functionality, collections, and tools "missing" from the Java standard library. implementation 'com.google.guava:guava:32.1.2-jre' // Trove supplies very efficient collections of primitive data types for Java. implementation 'net.sf.trove4j:trove4j:3.0.3' // TODO eliminate custom Conveyal geojson library, use Geotools? implementation 'com.conveyal:jackson2-geojson:0.9' implementation ('com.axiomalaska:polyline-encoder:0.2') { because 'Maintainer has updated this polyline library to match our dependencies (newer locationtech JTS).' } implementation 'javax.xml.bind:jaxb-api:2.3.1' // Google Protocol Buffers are used in decoding OSM data and seamless census data (in Geobuf format). // implementation 'com.google.protobuf:protobuf-java:3.13.0' // OSM PBF format support. Transitive dependency on Protobuf 3.12.2, // align with mapbox-vecor-tile and geobuf generated classes implementation 'org.openstreetmap.osmosis:osmosis-osm-binary:0.48.3' // Compressed bitmaps (bitsets) used to track which long OSM IDs have been encountered. implementation 'org.roaringbitmap:RoaringBitmap:0.7.3' ////// Test-only dependencies ////// // Java unit testing framework. testImplementation('org.junit.jupiter:junit-jupiter:5.9.2') // Chart drawing library for examining travel time distributions when crafting tests. // Although rarely used it should be low-impact: it is a test-only dependency with no transitive dependenices. testImplementation('org.jfree:jfreechart:1.5.1') // Load the test launcher, no longer automatic in Gradle 9: // https://github.com/gradle/gradle/issues/34512 testRuntimeOnly "org.junit.platform:junit-platform-launcher" }