aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Irina Iancu <elenairina@google.com>2016-11-24 16:23:50 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2016-11-25 12:20:21 +0000
commit5c9fcaf279f3912d1cd117fed4eeaf977b10644f (patch)
treecde0c36c286c99b9661f0a53306e0a2bcf259cc2 /src
parentbfa166b8964c3e72e84293231ad5e24d1c31d3bb (diff)
Introducing the Java compilation black box in Skylark.
Adding a new declared provider that will be the returning value of the Java compilation method in Skylark. This provider is considered a black-box from Skylark and it should only be passed around (returned from a rule/aspect implementation) to allow Java rules to depend on it. Also adding a new Skylark module (java_common) to allow retrieving the Java dependencies' black-box from Skylark implementations. -- MOS_MIGRATED_REVID=140138446
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/BUILD2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java67
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java39
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java33
-rw-r--r--src/test/java/com/google/devtools/build/lib/BUILD1
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java113
8 files changed, 241 insertions, 30 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 0fe30e15ed..3da2115a7f 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -761,8 +761,10 @@ java_library(
"rules/java/JavaLibrary.java",
"rules/java/JavaPlugin.java",
"rules/java/JavaPrimaryClassProvider.java",
+ "rules/java/JavaProvider.java",
"rules/java/JavaRuntimeClasspathProvider.java",
"rules/java/JavaRuntimeJarProvider.java",
+ "rules/java/JavaSkylarkCommon.java",
"rules/java/JavaSourceInfoProvider.java",
"rules/java/JavaToolchain.java",
"rules/java/JavaToolchainRule.java",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index ef69aefd5a..5881098ba5 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -109,6 +109,7 @@ import com.google.devtools.build.lib.rules.genquery.GenQueryRule;
import com.google.devtools.build.lib.rules.java.JavaConfigurationLoader;
import com.google.devtools.build.lib.rules.java.JavaImportBaseRule;
import com.google.devtools.build.lib.rules.java.JavaOptions;
+import com.google.devtools.build.lib.rules.java.JavaSkylarkCommon;
import com.google.devtools.build.lib.rules.java.JavaToolchainRule;
import com.google.devtools.build.lib.rules.java.JvmConfigurationLoader;
import com.google.devtools.build.lib.rules.java.ProguardLibraryRule;
@@ -522,6 +523,7 @@ public class BazelRuleClassProvider {
builder.addSkylarkAccessibleTopLevels("android_common", new AndroidSkylarkCommon());
builder.addSkylarkAccessibleTopLevels("java_proto_common", JavaProtoSkylarkCommon.class);
+ builder.addSkylarkAccessibleTopLevels("java_common", JavaSkylarkCommon.INSTANCE);
try {
builder.addWorkspaceFilePrefix(
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
index 857e83a362..213cf7606a 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
@@ -44,6 +44,7 @@ import com.google.devtools.build.lib.packages.RuleClass.PackageNameConstraint;
import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.packages.TriState;
import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider;
+import com.google.devtools.build.lib.rules.java.JavaProvider;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaToolchainProvider;
import com.google.devtools.build.lib.syntax.Type;
@@ -149,12 +150,20 @@ public class BazelJavaRuleClasses {
<a href="common-definitions.html#common-attributes">Attributes common to all build rules
</a>.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
- .override(builder.copy("deps")
- .allowedFileTypes(JavaSemantics.JAR)
- .allowedRuleClasses(ALLOWED_RULES_IN_DEPS)
- .mandatoryProviders(ImmutableList.of(
- SkylarkProviderIdentifier.forKey(CcLinkParamsProvider.CC_LINK_PARAMS.getKey())))
- .skipAnalysisTimeFileTypeCheck())
+ .override(
+ builder
+ .copy("deps")
+ .allowedFileTypes(JavaSemantics.JAR)
+ .allowedRuleClasses(ALLOWED_RULES_IN_DEPS)
+ .mandatoryProvidersList(
+ ImmutableList.of(
+ ImmutableList.of(
+ SkylarkProviderIdentifier.forKey(
+ CcLinkParamsProvider.CC_LINK_PARAMS.getKey())),
+ ImmutableList.of(
+ SkylarkProviderIdentifier.forKey(
+ JavaProvider.JAVA_PROVIDER.getKey()))))
+ .skipAnalysisTimeFileTypeCheck())
/* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(runtime_deps) -->
Libraries to make available to the final binary or test at runtime only.
Like ordinary <code>deps</code>, these will appear on the runtime classpath, but unlike
@@ -162,10 +171,11 @@ public class BazelJavaRuleClasses {
listed here. Dependency-analysis tools should ignore targets that appear in both
<code>runtime_deps</code> and <code>deps</code>.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
- .add(attr("runtime_deps", LABEL_LIST)
- .allowedFileTypes(JavaSemantics.JAR)
- .allowedRuleClasses(ALLOWED_RULES_IN_DEPS)
- .skipAnalysisTimeFileTypeCheck())
+ .add(
+ attr("runtime_deps", LABEL_LIST)
+ .allowedFileTypes(JavaSemantics.JAR)
+ .allowedRuleClasses(ALLOWED_RULES_IN_DEPS)
+ .skipAnalysisTimeFileTypeCheck())
/* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(srcs) -->
The list of source files that are processed to create the target.
@@ -195,11 +205,14 @@ public class BazelJavaRuleClasses {
class on the runtime classpath or you specify the <code>runtime_deps</code> argument.
</p>
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
- .add(attr("srcs", LABEL_LIST)
- .orderIndependent()
- .direct_compile_time_input()
- .allowedFileTypes(JavaSemantics.JAVA_SOURCE,
- JavaSemantics.SOURCE_JAR, JavaSemantics.PROPERTIES))
+ .add(
+ attr("srcs", LABEL_LIST)
+ .orderIndependent()
+ .direct_compile_time_input()
+ .allowedFileTypes(
+ JavaSemantics.JAVA_SOURCE,
+ JavaSemantics.SOURCE_JAR,
+ JavaSemantics.PROPERTIES))
/* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(resources) -->
A list of data files to include in a Java jar.
<p>
@@ -217,8 +230,10 @@ public class BazelJavaRuleClasses {
Resources may be source files or generated files.
</p>
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
- .add(attr("resources", LABEL_LIST).orderIndependent()
- .allowedFileTypes(FileTypeSet.ANY_FILE))
+ .add(
+ attr("resources", LABEL_LIST)
+ .orderIndependent()
+ .allowedFileTypes(FileTypeSet.ANY_FILE))
/* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(resource_strip_prefix) -->
The path prefix to strip from Java resources.
<p>
@@ -237,13 +252,17 @@ public class BazelJavaRuleClasses {
<code><a href="#java_library.exported_plugins">exported_plugins</a></code>. Resources
generated by the plugin will be included in the resulting jar of this rule.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
- .add(attr("plugins", LABEL_LIST).cfg(HOST).allowedRuleClasses("java_plugin")
- .legacyAllowAnyFileType())
- .add(attr(":java_plugins", LABEL_LIST)
- .cfg(HOST)
- .allowedRuleClasses("java_plugin")
- .silentRuleClassFilter()
- .value(JavaSemantics.JAVA_PLUGINS))
+ .add(
+ attr("plugins", LABEL_LIST)
+ .cfg(HOST)
+ .allowedRuleClasses("java_plugin")
+ .legacyAllowAnyFileType())
+ .add(
+ attr(":java_plugins", LABEL_LIST)
+ .cfg(HOST)
+ .allowedRuleClasses("java_plugin")
+ .silentRuleClassFilter()
+ .value(JavaSemantics.JAVA_PLUGINS))
/* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(javacopts) -->
Extra compiler options for this library.
Subject to <a href="make-variables.html">"Make variable"</a> substitution and
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
index 6104833c31..a8de642c9f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
@@ -24,7 +24,6 @@ import com.google.devtools.build.lib.analysis.RunfilesProvider;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.rules.cpp.CcLinkParams;
import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider;
@@ -169,6 +168,11 @@ public class JavaLibrary implements RuleConfiguredTargetFactory {
NestedSet<Artifact> proguardSpecs = new ProguardLibrary(ruleContext).collectProguardSpecs();
CcLinkParamsProvider ccLinkParamsProvider = new CcLinkParamsProvider(ccLinkParamsStore);
+ JavaCompilationArgsProvider compilationArgsProvider =
+ JavaCompilationArgsProvider.create(
+ javaCompilationArgs, recursiveJavaCompilationArgs,
+ compileTimeJavaDepArtifacts, runTimeJavaDepArtifacts);
+ JavaProvider javaProvider = new JavaProvider(compilationArgsProvider);
builder
.add(
JavaRuleOutputJarsProvider.class,
@@ -186,13 +190,11 @@ public class JavaLibrary implements RuleConfiguredTargetFactory {
.setFilesToBuild(filesToBuild)
.add(JavaNeverlinkInfoProvider.class, new JavaNeverlinkInfoProvider(neverLink))
.add(CppCompilationContext.class, transitiveCppDeps)
- .add(
- JavaCompilationArgsProvider.class,
- JavaCompilationArgsProvider.create(
- javaCompilationArgs, recursiveJavaCompilationArgs,
- compileTimeJavaDepArtifacts, runTimeJavaDepArtifacts))
+ .add(JavaCompilationArgsProvider.class, compilationArgsProvider)
+ .add(JavaProvider.class, javaProvider)
.add(CcLinkParamsProvider.class, ccLinkParamsProvider)
.addNativeDeclaredProvider(ccLinkParamsProvider)
+ .addNativeDeclaredProvider(javaProvider)
.add(
JavaNativeLibraryProvider.class,
new JavaNativeLibraryProvider(transitiveJavaNativeLibraries))
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java
new file mode 100644
index 0000000000..b6ee004893
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java
@@ -0,0 +1,39 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.lib.rules.java;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.SkylarkClassObject;
+import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor;
+
+/** A Skylark declared provider that encapsulates all providers that are needed by Java rules. */
+@Immutable
+public final class JavaProvider extends SkylarkClassObject implements TransitiveInfoProvider {
+
+ public static final SkylarkClassObjectConstructor JAVA_PROVIDER =
+ SkylarkClassObjectConstructor.createNative("java_common.provider");
+
+ private final JavaCompilationArgsProvider javaCompilationArgsProvider;
+
+ public JavaProvider(JavaCompilationArgsProvider javaCompilationArgsProvider) {
+ super(JAVA_PROVIDER, ImmutableMap.<String, Object>of());
+ this.javaCompilationArgsProvider = javaCompilationArgsProvider;
+ }
+
+ public JavaCompilationArgsProvider getJavaCompilationArgsProvider() {
+ return javaCompilationArgsProvider;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java
new file mode 100644
index 0000000000..7797ef5658
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java
@@ -0,0 +1,33 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.lib.rules.java;
+
+import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+
+/** A module that contains Skylark utilities for Java support. */
+@SkylarkModule(name = "java_common", doc = "Utilities for Java compilation support in Skylark.")
+public class JavaSkylarkCommon {
+ public static final JavaSkylarkCommon INSTANCE = new JavaSkylarkCommon();
+
+ @SkylarkCallable(
+ name = "provider",
+ structField = true,
+ doc = "Returns the Java declared provider."
+ )
+ public SkylarkClassObjectConstructor getJavaProvider() {
+ return JavaProvider.JAVA_PROVIDER;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 47e35eaf96..9fadf7f6f5 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -895,6 +895,7 @@ java_test(
"//src/main/java/com/google/devtools/build/lib:bazel-main",
"//src/main/java/com/google/devtools/build/lib:bazel-rules",
"//src/main/java/com/google/devtools/build/lib:build-base",
+ "//src/main/java/com/google/devtools/build/lib:collect",
"//src/main/java/com/google/devtools/build/lib:java-compilation",
"//src/main/java/com/google/devtools/build/lib:java-rules",
"//src/main/java/com/google/devtools/build/lib:packages-internal",
diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java
index 8a18f541d9..616fdb71b5 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java
@@ -22,8 +22,10 @@ import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.SkylarkProviders;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.packages.SkylarkClassObject;
import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor.SkylarkKey;
+import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
import org.junit.Test;
@@ -80,4 +82,115 @@ public class JavaSkylarkApiTest extends BuildViewTestCase {
assertThat((List<?>) skylarkClassObject.getValue("processor_classnames"))
.containsExactly("com.google.process.stuff");
}
+
+ @Test
+ public void cannotConstructJavaProvider() throws Exception {
+ scratch.file(
+ "foo/extension.bzl",
+ "my_provider = provider()",
+ "def _impl(ctx):",
+ " java_p = java_common.provider",
+ " dep_params = java_p()",
+ " return [my_provider(p = dep_params)]",
+ "my_rule = rule(_impl, attrs = { 'dep' : attr.label() })");
+ scratch.file("foo/BUILD", "load(':extension.bzl', 'my_rule')", "my_rule(name = 'r')");
+ reporter.removeHandler(failFastHandler);
+ assertThat(getConfiguredTarget("//foo:r")).isNull();
+ assertContainsEvent("'java_common.provider' cannot be constructed from Skylark");
+ }
+
+ @Test
+ public void javaProviderExposedOnJavaLibrary() throws Exception {
+ scratch.file(
+ "foo/extension.bzl",
+ "my_provider = provider()",
+ "def _impl(ctx):",
+ " dep_params = ctx.attr.dep[java_common.provider]",
+ " return [my_provider(p = dep_params)]",
+ "my_rule = rule(_impl, attrs = { 'dep' : attr.label() })");
+ scratch.file(
+ "foo/BUILD",
+ "load(':extension.bzl', 'my_rule')",
+ "java_library(name = 'jl', srcs = ['java/A.java'])",
+ "my_rule(name = 'r', dep = ':jl')");
+
+ ConfiguredTarget myRuleTarget = getConfiguredTarget("//foo:r");
+ ConfiguredTarget javaLibraryTarget = getConfiguredTarget("//foo:jl");
+ SkylarkKey myProviderKey =
+ new SkylarkKey(Label.parseAbsolute("//foo:extension.bzl"), "my_provider");
+ SkylarkClassObject declaredProvider =
+ myRuleTarget.getProvider(SkylarkProviders.class).getDeclaredProvider(myProviderKey);
+ Object javaProvider = declaredProvider.getValue("p");
+ assertThat(javaProvider).isInstanceOf(JavaProvider.class);
+ assertThat(javaLibraryTarget.getProvider(JavaProvider.class)).isEqualTo(javaProvider);
+ }
+
+ @Test
+ public void javaProviderPropagation() throws Exception {
+ scratch.file(
+ "foo/extension.bzl",
+ "def _impl(ctx):",
+ " dep_params = ctx.attr.dep[java_common.provider]",
+ " return [dep_params]",
+ "my_rule = rule(_impl, attrs = { 'dep' : attr.label() })");
+ scratch.file(
+ "foo/BUILD",
+ "load(':extension.bzl', 'my_rule')",
+ "java_library(name = 'jl', srcs = ['java/A.java'])",
+ "my_rule(name = 'r', dep = ':jl')",
+ "java_library(name = 'jl_top', srcs = ['java/C.java'], deps = [':r'])");
+
+ ConfiguredTarget myRuleTarget = getConfiguredTarget("//foo:r");
+ ConfiguredTarget javaLibraryTarget = getConfiguredTarget("//foo:jl");
+ ConfiguredTarget topJavaLibraryTarget = getConfiguredTarget("//foo:jl_top");
+
+ Object javaProvider = myRuleTarget.get(JavaProvider.JAVA_PROVIDER.getKey());
+ assertThat(javaProvider).isInstanceOf(JavaProvider.class);
+
+ JavaProvider jlJavaProvider = javaLibraryTarget.getProvider(JavaProvider.class);
+
+ assertThat(jlJavaProvider == javaProvider).isTrue();
+
+ JavaProvider jlTopJavaProvider = topJavaLibraryTarget.getProvider(JavaProvider.class);
+
+ javaCompilationArgsHaveTheSameParent(
+ jlJavaProvider.getJavaCompilationArgsProvider().getJavaCompilationArgs(),
+ jlTopJavaProvider.getJavaCompilationArgsProvider().getJavaCompilationArgs());
+ }
+
+ private static boolean javaCompilationArgsHaveTheSameParent(
+ JavaCompilationArgs args, JavaCompilationArgs otherArgs) {
+ if (!nestedSetsOfArtifactHaveTheSameParent(
+ args.getCompileTimeJars(), otherArgs.getCompileTimeJars())) {
+ return false;
+ }
+ if (!nestedSetsOfArtifactHaveTheSameParent(
+ args.getInstrumentationMetadata(), otherArgs.getInstrumentationMetadata())) {
+ return false;
+ }
+ if (!nestedSetsOfArtifactHaveTheSameParent(args.getRuntimeJars(), otherArgs.getRuntimeJars())) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean nestedSetsOfArtifactHaveTheSameParent(
+ NestedSet<Artifact> artifacts, NestedSet<Artifact> otherArtifacts) {
+ Iterator<Artifact> iterator = artifacts.iterator();
+ Iterator<Artifact> otherIterator = otherArtifacts.iterator();
+ while (iterator.hasNext() && otherIterator.hasNext()) {
+ Artifact artifact = (Artifact) iterator.next();
+ Artifact otherArtifact = (Artifact) otherIterator.next();
+ if (!artifact
+ .getPath()
+ .getParentDirectory()
+ .equals(otherArtifact.getPath().getParentDirectory())) {
+ return false;
+ }
+ }
+ if (iterator.hasNext() || otherIterator.hasNext()) {
+ return false;
+ }
+ return true;
+ }
} \ No newline at end of file