From e5889e11c4c8c8e6369a3f769a7595ea544b4a32 Mon Sep 17 00:00:00 2001 From: Advay Mengle Date: Tue, 25 Aug 2015 17:00:29 -0700 Subject: [PATCH] Automatic dependency resolution. Dependency configuration happens in 2 phases: - Dependency conversion: This converts your compile and testCompile dependencies into equivalent j2objcTranslation and j2objcLinkage dependencies. Namely local jars are copied to j2objcTranslation, external Maven jars are converted into their 'sources' form and copied to j2objcTranslation, and projects are copied to j2objcLinkage (they don't need translation). This phase is optional and controlled by j2objcConfig.autoConfigureDeps - Dependency resolution: This phase converts j2objcTranslation and j2objcLinkage deps into actual j2objc commands. Any source jar on j2objcTranslation is added to translateSourcepaths with --build-closure. Any project on j2objcLinkage is added to translateClasspaths and has its final j2objc static library linked in to this project's objective c code. This phase always runs. If your dependencies are too complicated for the plugin to figure out in the first phase, keep autoConfigureDeps=false, and just add the appropriate projets, jars, and libraries here. Also adds system tests for both project and external Maven dependencies. issue #180; Fixes #41; Fixes #372 TESTED=yes --- CHANGELOG.md | 15 ++- FAQ.md | 1 + .../j2objcgradle/DependencyConverter.groovy | 114 +++++++++++++++++ .../j2objcgradle/DependencyResolver.groovy | 113 +++++++++++++++++ .../j2objcgradle/J2objcConfig.groovy | 117 +++++++++++++----- .../j2objcgradle/J2objcPlugin.groovy | 17 +++ .../j2objcgradle/J2objcConfigTest.groovy | 5 + .../j2objcgradle/MultiProjectTest.groovy | 1 + .../multiProject1/extended/build.gradle | 5 +- .../main/java/com/example/ExtendedCube.java | 6 +- .../java/com/example/ExtendedCubeTest.java | 2 +- 11 files changed, 359 insertions(+), 37 deletions(-) create mode 100644 src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyConverter.groovy create mode 100644 src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyResolver.groovy diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b222151..ece279d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,20 @@ To see everything that has changed between version vA.B.C and vX.Y.Z, visit: https://github.com/j2objc-contrib/j2objc-gradle/compare/vA.B.C...vX.Y.Z -# Prelease Alphas +# Prerelease Alphas + +## vNext (HEAD) +Functionality: +* Automatic dependency resolution for Maven jars and Gradle projects #420 +* Proper limitation of functionality on non-Mac platforms #396 +* Embedded docs and versioning info for easier debugging #395 + +Code quality: +* Continuous integration on Mac #406 and on Windows #401 +* Added end to end tests on OSX (running j2objc) #409 #411 etc. +* Unit tests pass on Windows #404 +* Prevent publishing of bad releases #395 #398 +* Docs updates (various) ## v0.4.2-alpha Functionality: diff --git a/FAQ.md b/FAQ.md index 37a6437b..3ec0f652 100644 --- a/FAQ.md +++ b/FAQ.md @@ -31,6 +31,7 @@ Paste the results below, replacing existing contents. - [Error: implicit declaration of function 'JreRelease' is invalid in C99 [-Werror,-Wimplicit-function-declaration] JreRelease(this$0_)](#error-implicit-declaration-of-function-jrerelease-is-invalid-in-c99--werror-wimplicit-function-declaration-jrereleasethis0_) - [How do I disable a plugin task?](#how-do-i-disable-a-plugin-task) - [How do I setup dependencies with J2ObjC?](#how-do-i-setup-dependencies-with-j2objc) +- [How do I setup a dependency to a third-party Java library?](#how-do-i-setup-a-dependency-to-a-third-party-java-library) - [How do I setup a dependency on a Java project?](#how-do-i-setup-a-dependency-on-a-java-project) - [How do I setup a dependency on a prebuilt native library?](#how-do-i-setup-a-dependency-on-a-prebuilt-native-library) - [How do I setup a dependency on a native library project?](#how-do-i-setup-a-dependency-on-a-native-library-project) diff --git a/src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyConverter.groovy b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyConverter.groovy new file mode 100644 index 00000000..0ba1b747 --- /dev/null +++ b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyConverter.groovy @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015 the authors of j2objc-gradle (see AUTHORS file) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.j2objccontrib.j2objcgradle + +import groovy.transform.CompileStatic +import groovy.transform.PackageScope +import org.gradle.api.Project +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.SelfResolvingDependency + +/** + * Converts `[test]compile` dependencies to their + * `j2objcTranslation` and/or `j2objcLinkage` equivalents, depending on the type + * of dependency and whether or not they are already provided in native code. + *

+ * They will be resolved to appropriate `j2objc` constructs using DependencyResolver. + */ +@PackageScope +@CompileStatic +class DependencyConverter { + + final Project project + final J2objcConfig j2objcConfig + + // List of `group:name` + // TODO: Handle versioning. + static final List J2OBJC_DEFAULT_LIBS = [ + 'com.google.guava:guava', + 'junit:junit', + 'org.mockito:mockito-core', + 'com.google.j2objc:j2objc-annotations'] + + DependencyConverter(Project project, J2objcConfig j2objcConfig) { + this.project = project + this.j2objcConfig = j2objcConfig + } + + void configureAll() { + project.configurations.getByName('compile').dependencies.each { + visit(it) + } + project.configurations.getByName('testCompile').dependencies.each { + visit(it) + } + } + + protected void visit(Dependency dep) { + if (dep instanceof ProjectDependency) { + // ex. `compile project(':peer1')` + visitProjectDependency(dep as ProjectDependency) + } else if (dep instanceof SelfResolvingDependency) { + // ex. `compile fileTree(dir: 'libs', include: ['*.jar'])` + visitSelfResolvingDependency(dep as SelfResolvingDependency) + } else if (dep instanceof ExternalModuleDependency) { + // ex. `compile "com.google.code.gson:gson:2.3.1"` + visitExternalModuleDependency(dep as ExternalModuleDependency) + } else { + // Everything else + visitGenericDependency(dep) + } + } + + protected void visitSelfResolvingDependency( + SelfResolvingDependency dep) { + project.logger.debug("j2objc dependency converter: Translating file dep: $dep") + project.configurations.getByName('j2objcTranslation').dependencies.add( + dep.copy()) + } + + protected void visitProjectDependency(ProjectDependency dep) { + project.logger.debug("j2objc dependency converter: Linking Project: $dep") + project.configurations.getByName('j2objcLinkage').dependencies.add( + dep.copy()) + } + + protected void visitExternalModuleDependency(ExternalModuleDependency dep) { + project.logger.debug("j2objc dependency converter: External module dep: $dep") + // If the dep is already in the j2objc dist, ignore it. + if (J2OBJC_DEFAULT_LIBS.contains("${dep.group}:${dep.name}".toString())) { + // TODO: A more correct method might be converting these into our own + // form of SelfResolvingDependency that specifies which j2objc dist lib + // to use. + project.logger.debug("-- Skipped J2OBJC_DEFAULT_LIB: $dep") + return + } + project.logger.debug("-- Copied as source: $dep") + String group = dep.group == null ? '' : dep.group + String version = dep.version == null ? '' : dep.version + // TODO: Make this less fragile. What if sources don't exist for this artifact? + project.dependencies.add('j2objcTranslation', "${group}:${dep.name}:${version}:sources") + } + + protected void visitGenericDependency(Dependency dep) { + project.logger.warn("j2objc dependency converter: Unknown dependency type: $dep; copying naively") + project.configurations.getByName('j2objcTranslation').dependencies.add( + dep.copy()) + } +} diff --git a/src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyResolver.groovy b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyResolver.groovy new file mode 100644 index 00000000..9a5823e8 --- /dev/null +++ b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/DependencyResolver.groovy @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015 the authors of j2objc-gradle (see AUTHORS file) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.j2objccontrib.j2objcgradle + +import groovy.transform.CompileStatic +import groovy.transform.PackageScope +import org.gradle.api.InvalidUserDataException +import org.gradle.api.Project +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.SelfResolvingDependency +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.tasks.bundling.AbstractArchiveTask + +/** + * Resolves `j2objcTranslation` and 'j2objcLinkage' dependencies into their `j2objc` constructs. + */ +@PackageScope +@CompileStatic +class DependencyResolver { + + final Project project + final J2objcConfig j2objcConfig + + DependencyResolver(Project project, J2objcConfig j2objcConfig) { + this.project = project + this.j2objcConfig = j2objcConfig + } + + void configureAll() { + project.configurations.getByName('j2objcTranslation').each { File it -> + // These are the resolved files, NOT the dependencies themselves. + visitTranslateFile(it) + } + project.configurations.getByName('j2objcLinkage').dependencies.each { + visitLink(it) + } + } + + protected void visitTranslateFile(File depFile) { + j2objcConfig.translateSourcepaths(depFile.absolutePath) + j2objcConfig.enableBuildClosure() + } + + protected void visitLink(Dependency dep) { + if (dep instanceof ProjectDependency) { + visitLinkProjectDependency((ProjectDependency) dep) + } else if (dep instanceof SelfResolvingDependency) { + visitLinkSelfResolvingDependency((SelfResolvingDependency) dep) + } else { + visitLinkGenericDependency(dep) + } + } + + protected void visitLinkSelfResolvingDependency( + SelfResolvingDependency dep) { + // TODO: handle native prebuilt libraries as files. + throw new UnsupportedOperationException("Cannot automatically link J2ObjC dependency: $dep") + } + + protected void visitLinkProjectDependency(ProjectDependency dep) { + Project beforeProject = dep.dependencyProject + // We need to have j2objcConfig on the beforeProject configured first. + project.evaluationDependsOn beforeProject.path + + if (!beforeProject.plugins.hasPlugin(JavaPlugin)) { + String message = "$beforeProject is not a Java project.\n" + + "dependsOnJ2ObjcLib can only automatically resolve a\n" + + "dependency on a Java project also converted using the\n" + + "J2ObjC Gradle Plugin." + throw new InvalidUserDataException(message) + } + + if (!beforeProject.plugins.hasPlugin(J2objcPlugin)) { + String message = "$beforeProject does not use the J2ObjC Gradle Plugin.\n" + + "dependsOnJ2objcLib can be used only with another project that\n" + + "itself uses the J2ObjC Gradle Plugin." + throw new InvalidUserDataException(message) + } + + // Build and test the java/objc libraries and the objc headers of + // the other project first. + // Since we assert the presence of the J2objcPlugin above, + // we are guaranteed that the java plugin, which creates the jar task, + // is also present. + project.tasks.getByName('j2objcPreBuild').dependsOn { + return [beforeProject.tasks.getByName('j2objcBuild'), + beforeProject.tasks.getByName('jar')] + } + AbstractArchiveTask jarTask = beforeProject.tasks.getByName('jar') as AbstractArchiveTask + project.logger.debug("$project:j2objcTranslate must use ${jarTask.archivePath}") + j2objcConfig.translateClasspaths += jarTask.archivePath.absolutePath + j2objcConfig.nativeCompilation.dependsOnJ2objcLib(beforeProject) + } + + protected void visitLinkGenericDependency(Dependency dep) { + throw new UnsupportedOperationException("Cannot automatically link J2ObjC dependency: $dep") + } +} diff --git a/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfig.groovy b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfig.groovy index 47f28262..a526321c 100644 --- a/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfig.groovy +++ b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfig.groovy @@ -15,17 +15,15 @@ */ package com.github.j2objccontrib.j2objcgradle - import com.github.j2objccontrib.j2objcgradle.tasks.Utils import com.google.common.annotations.VisibleForTesting import groovy.transform.CompileStatic +import groovy.transform.TypeCheckingMode import org.gradle.api.InvalidUserDataException import org.gradle.api.Project import org.gradle.api.Task -import org.gradle.api.tasks.bundling.AbstractArchiveTask import org.gradle.api.tasks.util.PatternSet import org.gradle.util.ConfigureUtil - /** * j2objcConfig is used to configure the plugin with the project's build.gradle. * @@ -184,6 +182,17 @@ class J2objcConfig { appendArgs(this.translateArgs, 'translateArgs', translateArgs) } + /** + * Enables --build-closure, which translates classes referenced from the + * list of files passed for translation, using the + * {@link #translateSourcepaths}. + */ + void enableBuildClosure() { + if (!translateArgs.contains('--build-closure')) { + translateArgs('--build-closure') + } + } + /** * Local jars for translation e.g.: "lib/json-20140107.jar", "lib/somelib.jar". * This will be added to j2objc as a '-classpath' argument. @@ -227,6 +236,27 @@ class J2objcConfig { // the build breaks, you need to do a clean build. boolean UNSAFE_incrementalBuildClosure = false + /** + * Experimental functionality to automatically configure dependencies. + * Consider you have dependencies like: + *

+     * dependencies {
+     *     compile project(':peer1')                  // type (1)
+     *     compile 'com.google.code.gson:gson:2.3.1'  // type (3)
+     *     compile 'com.google.guava:guava:18.0'      // type (2)
+     *     testCompile 'junit:junit:4.11'             // type (2)
+     * }
+     * 
+ * Project dependencies (1) will be added as a `j2objcLink` dependency. + * Libraries already included in j2objc (2) will be ignored. + * External libraries in Maven (3) will be added in source JAR form to + * `j2objcTranslate`, and translated using `--build-closure`. + * Dependencies must be fully specified before you call finalConfigure(). + *

+ * This will become the default when stable in future releases. + */ + boolean autoConfigureDeps = false + /** * Additional libraries that are part of the j2objc distribution. *

@@ -292,8 +322,11 @@ class J2objcConfig { /** * @see #dependsOnJ2objcLib(org.gradle.api.Project) + * @deprecated Use `dependencies { j2objcLinkage project(':beforeProjectName') }` or + * `autoConfigDeps = true` instead. */ // TODO: Do this automatically based on project dependencies. + @Deprecated void dependsOnJ2objcLib(String beforeProjectName) { dependsOnJ2objcLib(project.project(beforeProjectName)) } @@ -311,33 +344,18 @@ class J2objcConfig { * Do not also include beforeProject's java source or jar in the * translateSourcepaths or translateClasspaths, respectively. Calling this method * is preferable and sufficient. + * + * @deprecated Use `dependencies { j2objcLinkage project(':beforeProjectName') }` or + * `autoConfigDeps=true` instead. */ - // TODO: Do this automatically based on project dependencies. + // TODO: Phase this API out, and have J2ObjC-applied project dependencies controlled + // solely via `j2objcLink` configuration. + @CompileStatic(TypeCheckingMode.SKIP) + @Deprecated void dependsOnJ2objcLib(Project beforeProject) { - // We need to have j2objcConfig on the beforeProject configured first. - project.evaluationDependsOn beforeProject.path - - if (!beforeProject.plugins.hasPlugin(J2objcPlugin)) { - String message = "$beforeProject does not use the J2ObjC Gradle Plugin.\n" + - "dependsOnJ2objcLib can be used only with another project that\n" + - "itself uses the J2ObjC Gradle Plugin." - throw new InvalidUserDataException(message) + project.dependencies { + j2objcLinkage beforeProject } - - // Build and test the java/objc libraries and the objc headers of - // the other project first. - // Since we assert the presence of the J2objcPlugin above, - // we are guaranteed that the java plugin, which creates the jar task, - // is also present. - project.tasks.getByName('j2objcPreBuild').dependsOn { - return [beforeProject.tasks.getByName('j2objcBuild'), - beforeProject.tasks.getByName('jar')] - } - AbstractArchiveTask jarTask = beforeProject.tasks.getByName('jar') as AbstractArchiveTask - project.logger.debug("$project:j2objcTranslate must use ${jarTask.archivePath}") - translateClasspaths += jarTask.archivePath.absolutePath - - nativeCompilation.dependsOnJ2objcLib(beforeProject) } /** @@ -538,22 +556,47 @@ class J2objcConfig { protected boolean finalConfigured = false /** - * Configures the native build using. Must be called at the very + * Configures the j2objc build. Must be called at the very * end of your j2objcConfig block. */ - // TODO: When Gradle makes it possible to modify a native build config - // after initial creation, we can remove this, and have methods on this object - // mutate the existing native model { } block. See: - // https://discuss.gradle.org/t/problem-with-model-block-when-switching-from-2-2-1-to-2-4/9937 @VisibleForTesting void finalConfigure() { - nativeCompilation.apply(project.file("${project.buildDir}/j2objcSrcGen")) + validateConfiguration() + // Conversion of compile and testCompile dependencies occurs optionally. + if (autoConfigureDeps) { + convertDeps() + } + // Resolution of j2objcTranslateSource dependencies occurs always. + // This lets users turn off autoConfigureDeps but manually set j2objcTranslateSource. + resolveDeps() + configureNativeCompilation() + configureTaskState() finalConfigured = true + } + protected void validateConfiguration() { assert destLibDir != null assert destSrcMainDir != null assert destSrcTestDir != null + } + + protected void configureNativeCompilation() { + // TODO: When Gradle makes it possible to modify a native build config + // after initial creation, we can remove this, and have methods on this object + // mutate the existing native model { } block. See: + // https://discuss.gradle.org/t/problem-with-model-block-when-switching-from-2-2-1-to-2-4/9937 + nativeCompilation.apply(project.file("${project.buildDir}/j2objcSrcGen")) + } + + protected void convertDeps() { + new DependencyConverter(project, this).configureAll() + } + + protected void resolveDeps() { + new DependencyResolver(project, this).configureAll() + } + protected void configureTaskState() { // Disable only if explicitly present and not true. boolean debugEnabled = Boolean.parseBoolean(Utils.getLocalProperty(project, 'debug.enabled', 'true')) boolean releaseEnabled = Boolean.parseBoolean(Utils.getLocalProperty(project, 'release.enabled', 'true')) @@ -623,4 +666,12 @@ class J2objcConfig { } } } + + @VisibleForTesting + void testingOnlyPrepConfigurations() { + // When testing we don't always want to apply the entire plugin + // before calling finalConfigure. + project.configurations.create('j2objcTranslation') + project.configurations.create('j2objcLinkage') + } } diff --git a/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcPlugin.groovy b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcPlugin.groovy index bfa22600..daf83412 100644 --- a/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcPlugin.groovy +++ b/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcPlugin.groovy @@ -85,6 +85,23 @@ class J2objcPlugin implements Plugin { // specified in j2objcConfig (or associated defaults in J2objcConfig). File j2objcSrcGenDir = file("${buildDir}/j2objcSrcGen") + // These configurations are groups of artifacts and dependencies for the plugin build + // https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.Configuration.html + configurations { + // When j2objcConfig.autoConfigureDeps is true, this configuration + // will have source paths automatically added to it. You can add + // *source* JARs/directories yourself as well. + j2objcTranslation { + description = 'J2ObjC Java source dependencies that need to be ' + + 'transitively translated via --build-closure' + } + // Currently, we can only handle Project dependencies already translated to Objective-C. + j2objcLinkage { + description = 'J2ObjC native library dependencies that need to be ' + + 'linked into the final library, and do not need translation' + } + } + // Produces a modest amount of output logging.captureStandardOutput LogLevel.INFO diff --git a/src/test/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfigTest.groovy b/src/test/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfigTest.groovy index 85b2d913..b4669481 100644 --- a/src/test/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfigTest.groovy +++ b/src/test/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfigTest.groovy @@ -80,6 +80,7 @@ class J2objcConfigTest { J2objcConfig ext = new J2objcConfig(proj) assert !ext.finalConfigured + ext.testingOnlyPrepConfigurations() ext.finalConfigure() assert ext.finalConfigured } @@ -91,6 +92,7 @@ class J2objcConfigTest { assert !ext.finalConfigured ext.translateOnlyMode = true + ext.testingOnlyPrepConfigurations() ext.finalConfigure() assert ext.finalConfigured } @@ -102,6 +104,7 @@ class J2objcConfigTest { assert !ext.finalConfigured ext.translateOnlyMode = true + ext.testingOnlyPrepConfigurations() ext.finalConfigure() assert ext.finalConfigured } @@ -116,6 +119,7 @@ class J2objcConfigTest { expectedException.expectMessage('Mac OS X is required for Native Compilation of translated code') assert !ext.finalConfigured + ext.testingOnlyPrepConfigurations() ext.finalConfigure() assert ext.finalConfigured } @@ -130,6 +134,7 @@ class J2objcConfigTest { expectedException.expectMessage('Mac OS X is required for Native Compilation of translated code') assert !ext.finalConfigured + ext.testingOnlyPrepConfigurations() ext.finalConfigure() assert ext.finalConfigured } diff --git a/src/test/groovy/com/github/j2objccontrib/j2objcgradle/MultiProjectTest.groovy b/src/test/groovy/com/github/j2objccontrib/j2objcgradle/MultiProjectTest.groovy index 0117af0b..85ca9cf1 100644 --- a/src/test/groovy/com/github/j2objccontrib/j2objcgradle/MultiProjectTest.groovy +++ b/src/test/groovy/com/github/j2objccontrib/j2objcgradle/MultiProjectTest.groovy @@ -45,6 +45,7 @@ class MultiProjectTest { @Test(expected = InvalidUserDataException) void twoProjectsWithDependsOnJ2objcLib_MissingPluginOnProject1() { j2objcConfig2.dependsOnJ2objcLib(proj1) + j2objcConfig2.finalConfigure() } @Test diff --git a/systemTests/multiProject1/extended/build.gradle b/systemTests/multiProject1/extended/build.gradle index 4102b325..c04325c8 100644 --- a/systemTests/multiProject1/extended/build.gradle +++ b/systemTests/multiProject1/extended/build.gradle @@ -25,11 +25,14 @@ dependencies { compile project(':base') // Intentionally testing e2e use of a built-in j2objc library, Guava. compile 'com.google.guava:guava:17.0' + // NOTE: this is an external dependency. The plugin automatically downloads the source, + // translates and links it in to the compiled library. No further configuration is required. + compile 'com.google.code.gson:gson:2.3.1' testCompile 'junit:junit:4.12' } j2objcConfig { - dependsOnJ2objcLib project(':base') + autoConfigureDeps true finalConfigure() } diff --git a/systemTests/multiProject1/extended/src/main/java/com/example/ExtendedCube.java b/systemTests/multiProject1/extended/src/main/java/com/example/ExtendedCube.java index 405df92d..87a9b0e6 100644 --- a/systemTests/multiProject1/extended/src/main/java/com/example/ExtendedCube.java +++ b/systemTests/multiProject1/extended/src/main/java/com/example/ExtendedCube.java @@ -18,6 +18,9 @@ import java.lang.Override; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + import com.google.common.base.Joiner; public class ExtendedCube extends Cube { @@ -28,7 +31,8 @@ public ExtendedCube(int dimension) { @Override public String toString() { - return String.format("[ExtendedCube %d]", dimension); + Gson gson = new GsonBuilder().create(); + return gson.toJson(this); } @Override diff --git a/systemTests/multiProject1/extended/src/test/java/com/example/ExtendedCubeTest.java b/systemTests/multiProject1/extended/src/test/java/com/example/ExtendedCubeTest.java index a79ffa03..b2722145 100644 --- a/systemTests/multiProject1/extended/src/test/java/com/example/ExtendedCubeTest.java +++ b/systemTests/multiProject1/extended/src/test/java/com/example/ExtendedCubeTest.java @@ -23,7 +23,7 @@ public class ExtendedCubeTest { @Test public void testToString() { - Assert.assertEquals("[ExtendedCube 7]", new ExtendedCube(7).toString()); + Assert.assertEquals("{\"dimension\":7}", new ExtendedCube(7).toString()); } @Test