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