From dcc910e270ed5b17504963312ef48b3491a178ad Mon Sep 17 00:00:00 2001 From: ronshapiro Date: Mon, 14 Nov 2016 14:57:29 -0800 Subject: [PATCH 1/3] Add opensource filegroups for all Dagger android code. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=139125765 --- android/pom.xml | 79 ++++++++++ .../src/main/java/test/android/InScope.java | 25 +++ .../test/android/ReleaseWhenModerate.java | 35 +++++ .../test/android/ReleaseWhenUiHidden.java | 35 +++++ .../main/java/test/android/TestComponent.java | 35 +++++ .../main/java/test/android/TestModule.java | 42 +++++ ...idMemorySensitiveReferenceManagerTest.java | 144 ++++++++++++++++++ android/src/main/AndroidManifest.xml | 19 +++ ...ndroidMemorySensitiveReferenceManager.java | 72 +++++++++ .../dagger/android/OnTrimMemoryValue.java | 49 ++++++ .../dagger/android/ReleaseReferencesAt.java | 63 ++++++++ pom.xml | 2 + 12 files changed, 600 insertions(+) create mode 100644 android/pom.xml create mode 100644 android/src/it/functional-tests/src/main/java/test/android/InScope.java create mode 100644 android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenModerate.java create mode 100644 android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenUiHidden.java create mode 100644 android/src/it/functional-tests/src/main/java/test/android/TestComponent.java create mode 100644 android/src/it/functional-tests/src/main/java/test/android/TestModule.java create mode 100644 android/src/it/functional-tests/src/test/java/test/android/AndroidMemorySensitiveReferenceManagerTest.java create mode 100644 android/src/main/AndroidManifest.xml create mode 100644 android/src/main/java/dagger/android/AndroidMemorySensitiveReferenceManager.java create mode 100644 android/src/main/java/dagger/android/OnTrimMemoryValue.java create mode 100644 android/src/main/java/dagger/android/ReleaseReferencesAt.java diff --git a/android/pom.xml b/android/pom.xml new file mode 100644 index 00000000000..0402608c5b8 --- /dev/null +++ b/android/pom.xml @@ -0,0 +1,79 @@ + + + + 4.0.0 + + + com.google.dagger + dagger-parent + HEAD-SNAPSHOT + + + dagger-android + Dagger for Android + + aar + + + 1.6 + + + + + android-support + file://${env.ANDROID_HOME}/extras/android/m2repository + + + + + + com.google.dagger + dagger + ${project.version} + + + com.google.android + android + provided + + + com.android.support + support-v4 + aar + + + com.android.support + support-annotations + + + + + + + com.simpligility.maven.plugins + android-maven-plugin + true + + + 24 + ${env.ANDROID_HOME} + + + + + + diff --git a/android/src/it/functional-tests/src/main/java/test/android/InScope.java b/android/src/it/functional-tests/src/main/java/test/android/InScope.java new file mode 100644 index 00000000000..6054add97c8 --- /dev/null +++ b/android/src/it/functional-tests/src/main/java/test/android/InScope.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 test.android; + +import java.lang.annotation.Annotation; +import javax.inject.Qualifier; + +@Qualifier +@interface InScope { + Class value(); +} diff --git a/android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenModerate.java b/android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenModerate.java new file mode 100644 index 00000000000..b5b100251f4 --- /dev/null +++ b/android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenModerate.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 test.android; + +import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import dagger.android.ReleaseReferencesAt; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.inject.Scope; + +@Documented +@Retention(RUNTIME) +@Target({TYPE, METHOD}) +@ReleaseReferencesAt(TRIM_MEMORY_MODERATE) +@Scope +@interface ReleaseWhenModerate {} diff --git a/android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenUiHidden.java b/android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenUiHidden.java new file mode 100644 index 00000000000..b3dfd17aa8d --- /dev/null +++ b/android/src/it/functional-tests/src/main/java/test/android/ReleaseWhenUiHidden.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 test.android; + +import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import dagger.android.ReleaseReferencesAt; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.inject.Scope; + +@Documented +@Retention(RUNTIME) +@Target({TYPE, METHOD}) +@ReleaseReferencesAt(TRIM_MEMORY_UI_HIDDEN) +@Scope +@interface ReleaseWhenUiHidden {} diff --git a/android/src/it/functional-tests/src/main/java/test/android/TestComponent.java b/android/src/it/functional-tests/src/main/java/test/android/TestComponent.java new file mode 100644 index 00000000000..c46420d07ad --- /dev/null +++ b/android/src/it/functional-tests/src/main/java/test/android/TestComponent.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 test.android; + +import dagger.Component; +import dagger.android.AndroidMemorySensitiveReferenceManager; +import javax.inject.Singleton; + +@Singleton +@ReleaseWhenUiHidden +@ReleaseWhenModerate +@Component(modules = TestModule.class) +interface TestComponent { + AndroidMemorySensitiveReferenceManager manager(); + + @InScope(ReleaseWhenUiHidden.class) + Object releasedWhenUiHidden(); + + @InScope(ReleaseWhenModerate.class) + Object releasedWhenModerate(); +} diff --git a/android/src/it/functional-tests/src/main/java/test/android/TestModule.java b/android/src/it/functional-tests/src/main/java/test/android/TestModule.java new file mode 100644 index 00000000000..7d7c59e6cbd --- /dev/null +++ b/android/src/it/functional-tests/src/main/java/test/android/TestModule.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 test.android; + +import dagger.Module; +import dagger.Provides; + +@Module +class TestModule { + int releasedWhenUiHiddenCalls; + int releasedWhenModerateCalls; + + @Provides + @ReleaseWhenUiHidden + @InScope(ReleaseWhenUiHidden.class) + Object releasedWhenUiHidden() { + ++releasedWhenUiHiddenCalls; + return new Object(); + } + + @Provides + @ReleaseWhenModerate + @InScope(ReleaseWhenModerate.class) + Object releasedWhenModerate() { + ++releasedWhenModerateCalls; + return new Object(); + } +} diff --git a/android/src/it/functional-tests/src/test/java/test/android/AndroidMemorySensitiveReferenceManagerTest.java b/android/src/it/functional-tests/src/test/java/test/android/AndroidMemorySensitiveReferenceManagerTest.java new file mode 100644 index 00000000000..bd95296fdc7 --- /dev/null +++ b/android/src/it/functional-tests/src/test/java/test/android/AndroidMemorySensitiveReferenceManagerTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 test.android; + +import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; +import static com.google.common.truth.Truth.assertThat; +import static test.android.AndroidMemorySensitiveReferenceManagerTest.AllWeakReferencesCleared.allWeakReferencesCleared; + +import com.google.common.collect.ImmutableList; +import com.google.common.testing.GcFinalization; +import com.google.common.testing.GcFinalization.FinalizationPredicate; +import java.lang.ref.WeakReference; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Functional tests of {@link dagger.android.AndroidMemorySensitiveReferenceManager}. */ +@RunWith(JUnit4.class) +public final class AndroidMemorySensitiveReferenceManagerTest { + + private TestModule testModule; + private TestComponent component; + + @Before + public void setUp() { + testModule = new TestModule(); + component = DaggerTestComponent.builder().testModule(testModule).build(); + } + + @Test + public void scoped() { + assertThat(component.releasedWhenUiHidden()).isSameAs(component.releasedWhenUiHidden()); + assertThat(component.releasedWhenModerate()).isSameAs(component.releasedWhenModerate()); + assertThat(testModule.releasedWhenUiHiddenCalls).isEqualTo(1); + assertThat(testModule.releasedWhenModerateCalls).isEqualTo(1); + } + + @Test + public void onTrimMemory_aboveThresholds() { + component.releasedWhenUiHidden(); + component.releasedWhenModerate(); + + component.manager().onTrimMemory(TRIM_MEMORY_COMPLETE); + GcFinalization.awaitDone( + allWeakReferencesCleared( + component.releasedWhenUiHidden(), component.releasedWhenModerate())); + + assertThat(component.releasedWhenUiHidden()).isSameAs(component.releasedWhenUiHidden()); + assertThat(component.releasedWhenModerate()).isSameAs(component.releasedWhenModerate()); + assertThat(testModule.releasedWhenUiHiddenCalls).isEqualTo(2); + assertThat(testModule.releasedWhenModerateCalls).isEqualTo(2); + } + + @Test + public void onTrimMemory_atOneThresholdBelowAnother() { + component.releasedWhenUiHidden(); + component.releasedWhenModerate(); + + component.manager().onTrimMemory(TRIM_MEMORY_UI_HIDDEN); + GcFinalization.awaitDone(allWeakReferencesCleared(component.releasedWhenUiHidden())); + + assertThat(component.releasedWhenUiHidden()).isSameAs(component.releasedWhenUiHidden()); + assertThat(component.releasedWhenModerate()).isSameAs(component.releasedWhenModerate()); + assertThat(testModule.releasedWhenUiHiddenCalls).isEqualTo(2); + assertThat(testModule.releasedWhenModerateCalls).isEqualTo(1); + } + + @Test + public void onTrimMemory_belowThresholds() { + component.releasedWhenUiHidden(); + component.releasedWhenModerate(); + assertThat(testModule.releasedWhenUiHiddenCalls).isEqualTo(1); + assertThat(testModule.releasedWhenModerateCalls).isEqualTo(1); + + component.manager().onTrimMemory(TRIM_MEMORY_RUNNING_MODERATE); + GcFinalization.awaitDone(allWeakReferencesCleared(new Object())); + + assertThat(component.releasedWhenUiHidden()).isSameAs(component.releasedWhenUiHidden()); + assertThat(component.releasedWhenModerate()).isSameAs(component.releasedWhenModerate()); + assertThat(testModule.releasedWhenUiHiddenCalls).isEqualTo(1); + assertThat(testModule.releasedWhenModerateCalls).isEqualTo(1); + } + + @Test + public void onTrimMemory_restore() { + component.releasedWhenUiHidden(); + component.releasedWhenModerate(); + assertThat(testModule.releasedWhenUiHiddenCalls).isEqualTo(1); + assertThat(testModule.releasedWhenModerateCalls).isEqualTo(1); + + component.manager().onTrimMemory(TRIM_MEMORY_UI_HIDDEN); + component.manager().onTrimMemory(TRIM_MEMORY_RUNNING_MODERATE); + GcFinalization.awaitDone(allWeakReferencesCleared(new Object())); + + assertThat(component.releasedWhenUiHidden()).isSameAs(component.releasedWhenUiHidden()); + assertThat(component.releasedWhenModerate()).isSameAs(component.releasedWhenModerate()); + assertThat(testModule.releasedWhenUiHiddenCalls).isEqualTo(1); + assertThat(testModule.releasedWhenModerateCalls).isEqualTo(1); + } + + static final class AllWeakReferencesCleared implements FinalizationPredicate { + + private final ImmutableList> references; + + AllWeakReferencesCleared(ImmutableList> references) { + this.references = references; + } + + @Override + public boolean isDone() { + for (WeakReference reference : references) { + if (reference.get() != null) { + return false; + } + } + return true; + } + + static AllWeakReferencesCleared allWeakReferencesCleared(Object... objects) { + ImmutableList.Builder> referencesBuilder = ImmutableList.builder(); + for (Object object : objects) { + referencesBuilder.add(new WeakReference<>(object)); + } + return new AllWeakReferencesCleared(referencesBuilder.build()); + } + } +} diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..5101105d103 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + diff --git a/android/src/main/java/dagger/android/AndroidMemorySensitiveReferenceManager.java b/android/src/main/java/dagger/android/AndroidMemorySensitiveReferenceManager.java new file mode 100644 index 00000000000..9a258787577 --- /dev/null +++ b/android/src/main/java/dagger/android/AndroidMemorySensitiveReferenceManager.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 dagger.android; + +import dagger.internal.Beta; +import dagger.internal.GwtIncompatible; +import dagger.releasablereferences.TypedReleasableReferenceManager; +import java.util.Set; +import javax.inject.Inject; + +/** + * Releases references in {@link ReleaseReferencesAt} {@linkplain javax.inject.Scope scopes} in + * low-memory conditions. + * + *

In order to release references in low-memory conditions, inject an {@code + * AndroidMemorySensitiveReferenceManager} into your {@link android.app.Application} and delegate + * {@link android.app.Application#onTrimMemory(int)} to it. + * + *

For example: + * + *

+ *   class MyApplication extends Application {
+ *     {@literal @Inject} AndroidMemorySensitiveReferenceManager manager;
+ *
+ *     public void onTrimMemory(int level) {
+ *       manager.onTrimMemory(level);
+ *     }
+ *   }
+ */ +@Beta +@GwtIncompatible +public final class AndroidMemorySensitiveReferenceManager { + + private final Set> managers; + + @Inject + AndroidMemorySensitiveReferenceManager( + Set> managers) { + this.managers = managers; + } + + /** + * Releases references for {@link ReleaseReferencesAt} scopes whose {@link + * ReleaseReferencesAt#value()} is less than or equal to {@code level}. Restores references for + * scopes whose {@link ReleaseReferencesAt#value()} is greater than {@code level}. + * + * @see android.app.Application#onTrimMemory(int) + */ + public void onTrimMemory(int level) { + for (TypedReleasableReferenceManager manager : managers) { + if (level >= manager.metadata().value()) { + manager.releaseStrongReferences(); + } else { + manager.restoreStrongReferences(); + } + } + } +} diff --git a/android/src/main/java/dagger/android/OnTrimMemoryValue.java b/android/src/main/java/dagger/android/OnTrimMemoryValue.java new file mode 100644 index 00000000000..9f918460e14 --- /dev/null +++ b/android/src/main/java/dagger/android/OnTrimMemoryValue.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 dagger.android; + +import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; +import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.content.ComponentCallbacks2; +import android.support.annotation.IntDef; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +/** + * Annotates an integer element to indicate that its value should be one of the constants defined in + * {@link ComponentCallbacks2}. + */ +@Documented +@Retention(SOURCE) +@IntDef({ + TRIM_MEMORY_BACKGROUND, + TRIM_MEMORY_COMPLETE, + TRIM_MEMORY_MODERATE, + TRIM_MEMORY_RUNNING_CRITICAL, + TRIM_MEMORY_RUNNING_CRITICAL, + TRIM_MEMORY_RUNNING_LOW, + TRIM_MEMORY_RUNNING_MODERATE, + TRIM_MEMORY_UI_HIDDEN +}) +@interface OnTrimMemoryValue {} diff --git a/android/src/main/java/dagger/android/ReleaseReferencesAt.java b/android/src/main/java/dagger/android/ReleaseReferencesAt.java new file mode 100644 index 00000000000..a0140e9af69 --- /dev/null +++ b/android/src/main/java/dagger/android/ReleaseReferencesAt.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 dagger.android; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; + +import dagger.internal.Beta; +import dagger.internal.GwtIncompatible; +import dagger.releasablereferences.CanReleaseReferences; +import java.lang.annotation.Documented; +import java.lang.annotation.Target; + +/** + * Annotates {@linkplain javax.inject.Scope scopes} to associate them with a low-memory threshold + * level, as described in {@link android.app.Application#onTrimMemory(int)}. + * + *

For example: + * + *

+ *   {@literal @Documented}
+ *   {@literal @Retention}(RUNTIME)
+ *   {@literal @Target}({TYPE, METHOD})
+ *   {@literal @ReleaseReferencesAt}(TRIM_MEMORY_BACKGROUND)
+ *   {@literal @Scope}
+ *   public {@literal @interface} MyScope {}
+ * + *

Any scope annotated with {@code @ReleaseReferencesAt} can {@linkplain CanReleaseReferences + * release its references}. + * + *

In order to release references in low-memory conditions, inject an {@link + * AndroidMemorySensitiveReferenceManager} into your {@link android.app.Application} and delegate + * {@link android.app.Application#onTrimMemory(int)} to it. + */ +@Beta +@Documented +@GwtIncompatible +@Target(ANNOTATION_TYPE) +@CanReleaseReferences +public @interface ReleaseReferencesAt { + /** + * If {@link AndroidMemorySensitiveReferenceManager#onTrimMemory(int)} is called with a value + * greater than or equal to this, the scope's references will be released. If it is called with a + * value less than this, the scope's references will be restored. + * + *

Use one of the constants defined in {@link android.content.ComponentCallbacks2}. + */ + @OnTrimMemoryValue + int value(); +} diff --git a/pom.xml b/pom.xml index 21217f5b8cd..04f0ebd7fbd 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ https://github.com/square/dagger + android compiler core gwt @@ -240,6 +241,7 @@ true + android core compiler gwt From 00a6fb136366cbe91a6869be062e9c8e83eba2b3 Mon Sep 17 00:00:00 2001 From: gak Date: Mon, 14 Nov 2016 23:33:06 -0800 Subject: [PATCH 2/3] Generate static methods in our factory implementations to provide a publicly accessible way to invoke package-private methods and constructors. Then, use those proxy methods directly to fulfill requests that don't require Providers. The interaction of this behavior + the existing behavior to invoke accessible elements directly yields 861 proxy accesses and 511 direct accesses in []' CommonDataReloadComponent for example. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=139167112 --- .../internal/codegen/Accessibility.java | 80 ++- .../dagger/internal/codegen/CodeBlocks.java | 40 +- .../internal/codegen/FactoryGenerator.java | 22 +- .../java/dagger/internal/codegen/Proxies.java | 252 ++++++++ .../SimpleMethodRequestFulfillment.java | 87 ++- .../dagger/internal/codegen/TypeNames.java | 12 +- .../codegen/InaccessibleTypeTest.java | 124 ++-- ...InjectConstructorFactoryGeneratorTest.java | 566 +++++++++-------- .../codegen/ModuleFactoryGeneratorTest.java | 583 ++++++++++-------- 9 files changed, 1150 insertions(+), 616 deletions(-) create mode 100644 compiler/src/main/java/dagger/internal/codegen/Proxies.java diff --git a/compiler/src/main/java/dagger/internal/codegen/Accessibility.java b/compiler/src/main/java/dagger/internal/codegen/Accessibility.java index bdc921d2be5..a56222ff600 100644 --- a/compiler/src/main/java/dagger/internal/codegen/Accessibility.java +++ b/compiler/src/main/java/dagger/internal/codegen/Accessibility.java @@ -22,6 +22,7 @@ import static javax.lang.model.element.Modifier.PUBLIC; import com.google.auto.common.MoreElements; +import com.google.common.base.Optional; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; @@ -36,9 +37,11 @@ import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVariable; +import javax.lang.model.type.TypeVisitor; import javax.lang.model.type.WildcardType; import javax.lang.model.util.SimpleElementVisitor6; import javax.lang.model.util.SimpleTypeVisitor6; +import javax.lang.model.util.SimpleTypeVisitor8; /** * Utility methods for determining whether a {@linkplain TypeMirror type} or an {@linkplain Element @@ -56,17 +59,35 @@ * preferable for {@code javac}. */ final class Accessibility { + /** * Returns true if the given type can be referenced from code in the given package. */ static boolean isTypeAccessibleFrom(TypeMirror type, String packageName) { - return type.accept(new TypeAccessiblityVisitor(packageName), null); + return type.accept(new TypeAccessibilityVisitor(packageName), null); + } + + /** Returns true if the given type can be referenced from any package. */ + static boolean isTypePubliclyAccessible(TypeMirror type) { + return type.accept(new TypeAccessibilityVisitor(), null); } - private static final class TypeAccessiblityVisitor extends SimpleTypeVisitor6 { - final String packageName; + private static boolean isTypeAccessibleFrom(TypeMirror type, Optional packageName) { + return type.accept(new TypeAccessibilityVisitor(packageName), null); + } + + private static final class TypeAccessibilityVisitor extends SimpleTypeVisitor6 { + final Optional packageName; + + TypeAccessibilityVisitor() { + this(Optional.absent()); + } + + TypeAccessibilityVisitor(String packageName) { + this(Optional.of(packageName)); + } - TypeAccessiblityVisitor(String packageName) { + TypeAccessibilityVisitor(Optional packageName) { this.packageName = packageName; } @@ -135,11 +156,18 @@ protected Boolean defaultAction(TypeMirror type, Void p) { } } - /** - * Returns true if the given element can be referenced from code in the given package. - */ + /** Returns true if the given element can be referenced from code in the given package. */ //TODO(gak): account for protected - static boolean isElementAccessibleFrom(Element element, final String packageName) { + static boolean isElementAccessibleFrom(Element element, String packageName) { + return element.accept(new ElementAccessibilityVisitor(packageName), null); + } + + /** Returns true if the given element can be referenced from any package. */ + static boolean isElementPubliclyAccessible(Element element) { + return element.accept(new ElementAccessibilityVisitor(), null); + } + + private static boolean isElementAccessibleFrom(Element element, Optional packageName) { return element.accept(new ElementAccessibilityVisitor(packageName), null); } @@ -151,9 +179,17 @@ static boolean isElementAccessibleFromOwnPackage(Element element) { private static final class ElementAccessibilityVisitor extends SimpleElementVisitor6 { - final String packageName; + final Optional packageName; + + ElementAccessibilityVisitor() { + this(Optional.absent()); + } ElementAccessibilityVisitor(String packageName) { + this(Optional.of(packageName)); + } + + ElementAccessibilityVisitor(Optional packageName) { this.packageName = packageName; } @@ -189,7 +225,8 @@ boolean accessibleModifiers(Element element) { return true; } else if (element.getModifiers().contains(PRIVATE)) { return false; - } else if (getPackage(element).getQualifiedName().contentEquals(packageName)) { + } else if (packageName.isPresent() + && getPackage(element).getQualifiedName().contentEquals(packageName.get())) { return true; } else { return false; @@ -215,6 +252,29 @@ public Boolean visitVariable(VariableElement element, Void p) { } } + private static final TypeVisitor> RAW_TYPE_ACCESSIBILITY_VISITOR = + new SimpleTypeVisitor8>() { + @Override + protected Boolean defaultAction(TypeMirror e, Optional requestingPackage) { + return isTypeAccessibleFrom(e, requestingPackage); + } + + @Override + public Boolean visitDeclared(DeclaredType t, Optional requestingPackage) { + return isElementAccessibleFrom(t.asElement(), requestingPackage); + } + }; + + /** Returns true if the raw type of {@code type} is accessible from the given package. */ + static boolean isRawTypeAccessible(TypeMirror type, String requestingPackage) { + return type.accept(RAW_TYPE_ACCESSIBILITY_VISITOR, Optional.of(requestingPackage)); + } + + /** Returns true if the raw type of {@code type} is accessible from any package. */ + static boolean isRawTypePubliclyAccessible(TypeMirror type) { + return type.accept(RAW_TYPE_ACCESSIBILITY_VISITOR, Optional.absent()); + } + private Accessibility() {} } diff --git a/compiler/src/main/java/dagger/internal/codegen/CodeBlocks.java b/compiler/src/main/java/dagger/internal/codegen/CodeBlocks.java index 7c8bf0eecde..9a54dc23851 100644 --- a/compiler/src/main/java/dagger/internal/codegen/CodeBlocks.java +++ b/compiler/src/main/java/dagger/internal/codegen/CodeBlocks.java @@ -18,14 +18,16 @@ import com.google.common.collect.FluentIterable; import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.TypeName; import java.util.Iterator; +import java.util.Spliterator; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; final class CodeBlocks { - /** - * Returns a comma-separated version of {@code codeBlocks} as one unified {@link CodeBlock}. - */ + /** Returns a comma-separated version of {@code codeBlocks} as one unified {@link CodeBlock}. */ static CodeBlock makeParametersCodeBlock(Iterable codeBlocks) { return join(codeBlocks, ", "); } @@ -62,5 +64,37 @@ static CodeBlock stringLiteral(String toWrap) { return CodeBlock.of("$S", toWrap); } + /** Returns a javadoc {@literal @link} tag that poins to the given {@link ExecutableElement}. */ + static CodeBlock javadocLinkTo(ExecutableElement executableElement) { + CodeBlock.Builder builder = + CodeBlock.builder().add("{@link $T#", executableElement.getEnclosingElement()); + switch (executableElement.getKind()) { + case METHOD: + builder.add("$L", executableElement.getSimpleName()); + break; + case CONSTRUCTOR: + builder.add("$L", executableElement.getEnclosingElement().getSimpleName()); + break; + case STATIC_INIT: + case INSTANCE_INIT: + throw new IllegalArgumentException( + "cannot create a javadoc link to an initializer: " + executableElement); + default: + throw new AssertionError(executableElement.toString()); + } + builder.add("("); + Spliterator rawTypesSpliterator = + executableElement + .getParameters() + .stream() + .map(VariableElement::asType) + .map(TypeName::get) + .map(TypeNames::rawTypeName) + .spliterator(); + rawTypesSpliterator.tryAdvance(first -> builder.add("$T", first)); + rawTypesSpliterator.forEachRemaining(remaining -> builder.add(", $T", remaining)); + return builder.add(")}").build(); + } + private CodeBlocks() {} } diff --git a/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java b/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java index 13504f3a212..5513ae77be1 100644 --- a/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java +++ b/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java @@ -27,6 +27,8 @@ import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION; import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION; import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD; +import static dagger.internal.codegen.Proxies.createProxy; +import static dagger.internal.codegen.Proxies.shouldGenerateProxy; import static dagger.internal.codegen.SourceFiles.bindingTypeElementTypeVariableNames; import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement; import static dagger.internal.codegen.SourceFiles.generateBindingFieldsForDependencies; @@ -38,6 +40,7 @@ import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; +import com.google.auto.common.MoreElements; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -60,6 +63,7 @@ import javax.annotation.processing.Filer; import javax.inject.Inject; import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; import javax.lang.model.util.Elements; import javax.tools.Diagnostic; @@ -270,10 +274,26 @@ Optional write(ClassName generatedTypeName, ProvisionBinding b factoryBuilder.addMethod(createMethod.get()); } - // TODO(gak): write a sensible toString + proxyMethodFor(binding).asSet().forEach(factoryBuilder::addMethod); + return Optional.of(factoryBuilder); } + /** + * Returns a method to proxy access to the binding's {@link Binding#bindingElement()}, which + * behaves according to the description in {@link Proxies}. Use here is further restricted by + * whether or not members injection is required, since that is not yet implemented for proxy + * methods, but will be added. + */ + // TODO(gak): support accessibility proxies for types with injected members as well + private static Optional proxyMethodFor(ProvisionBinding binding) { + ExecutableElement executableElement = MoreElements.asExecutable(binding.bindingElement().get()); + if (binding.membersInjectionRequest().isPresent() || !shouldGenerateProxy(executableElement)) { + return Optional.absent(); + } + return Optional.of(createProxy(executableElement)); + } + @CanIgnoreReturnValue private FieldSpec addConstructorParameterAndTypeField( TypeName typeName, diff --git a/compiler/src/main/java/dagger/internal/codegen/Proxies.java b/compiler/src/main/java/dagger/internal/codegen/Proxies.java new file mode 100644 index 00000000000..800e3272d4e --- /dev/null +++ b/compiler/src/main/java/dagger/internal/codegen/Proxies.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2016 The Dagger Authors. + * + * 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 dagger.internal.codegen; + +import static com.google.common.base.CaseFormat.LOWER_CAMEL; +import static com.google.common.base.CaseFormat.UPPER_CAMEL; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.Iterables.toArray; +import static com.squareup.javapoet.MethodSpec.methodBuilder; +import static dagger.internal.codegen.Accessibility.isElementAccessibleFrom; +import static dagger.internal.codegen.Accessibility.isElementPubliclyAccessible; +import static dagger.internal.codegen.Accessibility.isRawTypeAccessible; +import static dagger.internal.codegen.Accessibility.isRawTypePubliclyAccessible; +import static dagger.internal.codegen.Accessibility.isTypePubliclyAccessible; +import static dagger.internal.codegen.CodeBlocks.javadocLinkTo; +import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock; +import static dagger.internal.codegen.TypeNames.rawTypeName; +import static javax.lang.model.element.Modifier.PUBLIC; +import static javax.lang.model.element.Modifier.STATIC; +import static javax.lang.model.type.TypeKind.VOID; + +import com.google.auto.common.MoreElements; +import com.google.common.collect.ImmutableList; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeVariableName; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.Parameterizable; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + +/** + * Proxy methods ("proxies") are generated methods used to give component implementations access to + * {@link Element}s that are inaccessible as written in the source code. For example, a component + * cannot directly invoke a package-private {@code @Inject} constructor in a different package. + * + *

Since proxies are generated separately from their usages, they cannot make any assumptions + * about the types or packages from which methods will be invoked. Thus, any type or element that is + * not public is considered to be "inaccessible". + * + *

This class generates proxies for any {@link ExecutableElement}, but the form of the methods + * are somewhat tailored to how they are used within components. + * + *

Proxies have the following attributes: + * + *

    + *
  • Proxies are always {@code public}, {@code static} methods. + *
  • The return type of the proxy is always the return type of the method or the constructed + * type regardless of its accessibility. For example, if a proxied method returns {@code + * MyPackagePrivateClass}, the proxy method will also return {@code MyPackagePrivateClass} + * because the accessibility of the return type does not impact callers. + *
  • Proxies for constructors are named "{@code newTypeName}" (where "{@code TypeName}" is the + * name of the type being constructed) and proxies for methods are named "{@code + * proxyMethodName}" (where "{@code methodName}" is the name of the method being proxied). + *
  • If the element being proxied is an instance method, the first parameter will be the + * instance. + *
  • The rest of the parameters of the proxy method are that of the proxied method unless the + * raw type of a parameter is inaccessible, in which case it is {@link Object}. Passing an + * object to this method that is not of the proxied parameter type will result in a {@link + * ClassCastException}. + *

    While it is not required by the language that a method's parameter types be accessible + * to invoke it, components often hold references to {@link javax.inject.Provider} as raw + * types in order to dodge similar accessibility restrictions. This means that the {@code + * {@link javax.inject.Provider#get()}} method will return {@link Object}. Since it cannot be + * cast to the the more specific type on the calling side, we must accept {@link Object} in + * the proxy method. + *

+ * + *

Proxies are not generated under the following conditions: + * + *

    + *
  • If an {@link ExecutableElement} is publicly accessible and all of its {@linkplain + * ExecutableElement#getParameters() parameters} are publicly accessible types, no proxy is + * necessary. If the type of a parameter has a type argument that is is inaccessible, but the + * raw type that is accessible, the type is considered to be accessible because callers can + * always hold references to the raw type. + *
  • If an {@link ExecutableElement} or any of its enclosing types are {@code private}, no proxy + * is generated because it is impossible to write Java (without reflection) that accesses the + * element. + *
+ */ +final class Proxies { + + /** + * Returns {@code true} if the given method has limited access, thus requiring a proxy for some + * cases. + */ + static boolean shouldGenerateProxy(ExecutableElement method) { + return !isElementPubliclyAccessible(method) + || method + .getParameters() + .stream() + .map(VariableElement::asType) + .anyMatch(type -> !isRawTypePubliclyAccessible(type)); + } + + /** Returns {@code true} if accessing the given method from the given package requires a proxy. */ + static boolean requiresProxyAccess(ExecutableElement method, String callingPackage) { + return !isElementAccessibleFrom(method, callingPackage) + || method + .getParameters() + .stream() + .map(VariableElement::asType) + .anyMatch(type -> !isRawTypeAccessible(type, callingPackage)); + } + + /** Returns the name of the method that proxies access to the given method. */ + static String proxyName(ExecutableElement method) { + switch (method.getKind()) { + case CONSTRUCTOR: + return "new" + method.getEnclosingElement().getSimpleName(); + case METHOD: + return "proxy" + LOWER_CAMEL.to(UPPER_CAMEL, method.getSimpleName().toString()); + case STATIC_INIT: + case INSTANCE_INIT: + throw new IllegalArgumentException( + "cannot proxy initializers because they cannot be invoked directly: " + method); + default: + throw new AssertionError(method); + } + } + + /** + * Returns a proxy method implementation for the method. + * + * @throws IllegalArgumentException if the method is publicly accessible + */ + // TODO(gak): expand support to proxy fields + static MethodSpec createProxy(ExecutableElement method) { + checkArgument( + shouldGenerateProxy(method), + "method and all of its arguments are accessible; proxy isn't necessary: %s", + method); + final MethodSpec.Builder builder; + switch (method.getKind()) { + case CONSTRUCTOR: + builder = forConstructor(method); + break; + case METHOD: + builder = forMethod(method); + break; + default: + throw new AssertionError(); + } + builder.addJavadoc("Proxies $L.", javadocLinkTo(method)); + builder.addModifiers(PUBLIC, STATIC); + + copyTypeParameters(method, builder); + copyThrows(method, builder); + + return builder.build(); + } + + private static MethodSpec.Builder forConstructor(ExecutableElement constructor) { + TypeElement enclosingType = MoreElements.asType(constructor.getEnclosingElement()); + MethodSpec.Builder methodBuilder = methodBuilder(proxyName(constructor)); + + copyTypeParameters(enclosingType, methodBuilder); + + methodBuilder.returns(TypeName.get(enclosingType.asType())); + + CodeBlock arguments = + copyParameters( + constructor, methodBuilder, new UniqueNameSet(), new ImmutableList.Builder<>()); + + methodBuilder.addCode("return new $T($L);", enclosingType, arguments); + + return methodBuilder; + } + + private static MethodSpec.Builder forMethod(ExecutableElement method) { + TypeElement enclosingType = MoreElements.asType(method.getEnclosingElement()); + MethodSpec.Builder methodBuilder = methodBuilder(proxyName(method)); + + UniqueNameSet nameSet = new UniqueNameSet(); + ImmutableList.Builder argumentsBuilder = new ImmutableList.Builder<>(); + if (!method.getModifiers().contains(STATIC)) { + methodBuilder.addParameter( + TypeName.get(enclosingType.asType()), nameSet.getUniqueName("instance")); + } + CodeBlock arguments = copyParameters(method, methodBuilder, nameSet, argumentsBuilder); + if (!method.getReturnType().getKind().equals(VOID)) { + methodBuilder.addCode("return "); + } + if (method.getModifiers().contains(STATIC)) { + methodBuilder.addCode("$T", rawTypeName(TypeName.get(enclosingType.asType()))); + } else { + copyTypeParameters(enclosingType, methodBuilder); + // "instance" is guaranteed b/c it was the first name into the UniqueNameSet + methodBuilder.addCode("instance", method.getSimpleName()); + } + methodBuilder.addCode(".$N($L);", method.getSimpleName(), arguments); + methodBuilder.returns(TypeName.get(method.getReturnType())); + return methodBuilder; + } + + private static void copyThrows(ExecutableElement method, MethodSpec.Builder methodBuilder) { + for (TypeMirror thrownType : method.getThrownTypes()) { + methodBuilder.addException(TypeName.get(thrownType)); + } + } + + private static CodeBlock copyParameters( + ExecutableElement method, + MethodSpec.Builder methodBuilder, + UniqueNameSet nameSet, + ImmutableList.Builder argumentsBuilder) { + for (VariableElement parameter : method.getParameters()) { + TypeMirror parameterType = parameter.asType(); + boolean useObject = !isTypePubliclyAccessible(parameterType); + TypeName typeName = useObject ? TypeName.OBJECT : TypeName.get(parameterType); + String name = nameSet.getUniqueName(parameter.getSimpleName().toString()); + argumentsBuilder.add( + useObject ? CodeBlock.of("($T) $L", parameterType, name) : CodeBlock.of(name)); + ParameterSpec.Builder parameterBuilder = + ParameterSpec.builder(typeName, name) + .addModifiers(toArray(parameter.getModifiers(), Modifier.class)); + methodBuilder.addParameter(parameterBuilder.build()); + } + methodBuilder.varargs(method.isVarArgs()); + return makeParametersCodeBlock(argumentsBuilder.build()); + } + + private static void copyTypeParameters( + Parameterizable parameterizable, MethodSpec.Builder methodBuilder) { + for (TypeParameterElement typeParameterElement : parameterizable.getTypeParameters()) { + methodBuilder.addTypeVariable(TypeVariableName.get(typeParameterElement)); + } + } + + private Proxies() {} +} diff --git a/compiler/src/main/java/dagger/internal/codegen/SimpleMethodRequestFulfillment.java b/compiler/src/main/java/dagger/internal/codegen/SimpleMethodRequestFulfillment.java index e6f04098447..add65fd31b3 100644 --- a/compiler/src/main/java/dagger/internal/codegen/SimpleMethodRequestFulfillment.java +++ b/compiler/src/main/java/dagger/internal/codegen/SimpleMethodRequestFulfillment.java @@ -19,20 +19,22 @@ import static com.google.auto.common.MoreElements.asExecutable; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; -import static dagger.internal.codegen.Accessibility.isElementAccessibleFrom; import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom; +import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock; +import static dagger.internal.codegen.Proxies.proxyName; +import static dagger.internal.codegen.Proxies.requiresProxyAccess; +import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding; +import static dagger.internal.codegen.TypeNames.rawTypeName; +import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; import static javax.lang.model.element.Modifier.STATIC; import com.google.common.util.concurrent.Futures; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; -import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import javax.lang.model.element.ExecutableElement; -import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.SimpleTypeVisitor8; /** * A request fulfillment implementation that invokes methods or constructors directly to fulfill @@ -64,69 +66,38 @@ final class SimpleMethodRequestFulfillment extends RequestFulfillment { @Override CodeBlock getSnippetForDependencyRequest(DependencyRequest request, ClassName requestingClass) { - String requestingPackage = requestingClass.packageName(); - /* This is where we do some checking to make sure we honor and/or dodge accessibility - * restrictions: - * - * 1. Check to make sure that the method/constructor that we're trying to invoke is accessible. - * 2. Check that the *raw type* of each parameter is accessible. If something is only - * inaccessible due to a type variable, we do a raw type cast just like we do for framework - * types. - */ - // TODO(gak): the accessibility limitation here needs to be addressed - if (!isElementAccessibleFrom(provisionBinding.bindingElement().get(), requestingPackage) - || provisionBinding - .dependencies() - .stream() - .anyMatch( - dependencyRequest -> - !isRawTypeAccessible(dependencyRequest.key().type(), requestingPackage))) { - return providerDelegate.getSnippetForDependencyRequest(request, requestingClass); - } switch (request.kind()) { case INSTANCE: - return invokeMethod(requestingClass); + return invokeMethodOrProxy(requestingClass); case FUTURE: - return CodeBlock.of("$T.immediateFuture($L)", Futures.class, invokeMethod(requestingClass)); + return CodeBlock.of( + "$T.immediateFuture($L)", Futures.class, invokeMethodOrProxy(requestingClass)); default: return providerDelegate.getSnippetForDependencyRequest(request, requestingClass); } } - public static final SimpleTypeVisitor8 RAW_TYPE_ACCESSIBILITY_VISITOR = - new SimpleTypeVisitor8() { - @Override - protected Boolean defaultAction(TypeMirror e, String requestingPackage) { - return isTypeAccessibleFrom(e, requestingPackage); - } - - @Override - public Boolean visitDeclared(DeclaredType t, String requestingPackage) { - return isElementAccessibleFrom(t.asElement(), requestingPackage); - } - }; - - private static boolean isRawTypeAccessible(TypeMirror type, String requestingPackage) { - return type.accept(RAW_TYPE_ACCESSIBILITY_VISITOR, requestingPackage); + private CodeBlock invokeMethodOrProxy(ClassName requestingClass) { + ExecutableElement bindingElement = asExecutable(provisionBinding.bindingElement().get()); + return requiresProxyAccess(bindingElement, requestingClass.packageName()) + ? invokeProxyMethod(requestingClass) + : invokeMethod(requestingClass); } private CodeBlock invokeMethod(ClassName requestingClass) { CodeBlock parametersCodeBlock = - CodeBlocks.makeParametersCodeBlock( + makeParametersCodeBlock( provisionBinding .explicitDependencies() .stream() .map( request -> { - CodeBlock snippet = - registry - .getRequestFulfillment(request.bindingKey()) - .getSnippetForDependencyRequest(request, requestingClass); - return isTypeAccessibleFrom( - request.key().type(), requestingClass.packageName()) + CodeBlock snippet = getDependencySnippet(requestingClass, request); + TypeMirror requestElementType = request.requestElement().get().asType(); + return isTypeAccessibleFrom(requestElementType, requestingClass.packageName()) ? snippet : CodeBlock.of( - "($T) $L", rawTypeName(TypeName.get(request.key().type())), snippet); + "($T) $L", rawTypeName(TypeName.get(requestElementType)), snippet); }) .collect(toList())); // we use the type from the key to ensure we get the right generics @@ -147,9 +118,21 @@ private CodeBlock invokeMethod(ClassName requestingClass) { } } - private static TypeName rawTypeName(TypeName typeName) { - return (typeName instanceof ParameterizedTypeName) - ? ((ParameterizedTypeName) typeName).rawType - : typeName; + private CodeBlock invokeProxyMethod(ClassName requestingClass) { + return CodeBlock.of( + "$T.$L($L)", + generatedClassNameForBinding(provisionBinding), + proxyName(asExecutable(provisionBinding.bindingElement().get())), + provisionBinding + .explicitDependencies() + .stream() + .map(request -> getDependencySnippet(requestingClass, request)) + .collect(collectingAndThen(toList(), CodeBlocks::makeParametersCodeBlock))); + } + + private CodeBlock getDependencySnippet(ClassName requestingClass, DependencyRequest request) { + return registry + .getRequestFulfillment(request.bindingKey()) + .getSnippetForDependencyRequest(request, requestingClass); } } diff --git a/compiler/src/main/java/dagger/internal/codegen/TypeNames.java b/compiler/src/main/java/dagger/internal/codegen/TypeNames.java index 6003cc128eb..3c427b0bb94 100644 --- a/compiler/src/main/java/dagger/internal/codegen/TypeNames.java +++ b/compiler/src/main/java/dagger/internal/codegen/TypeNames.java @@ -156,6 +156,16 @@ static ParameterizedTypeName providerOf(TypeName typeName) { static ParameterizedTypeName setOf(TypeName elementType) { return ParameterizedTypeName.get(SET, elementType); } - + + /** + * Returns the {@link TypeName} for the raw type of the given type name. If the argument isn't a + * parameterized type, it returns the argument unchanged. + */ + static TypeName rawTypeName(TypeName typeName) { + return (typeName instanceof ParameterizedTypeName) + ? ((ParameterizedTypeName) typeName).rawType + : typeName; + } + private TypeNames() {} } diff --git a/compiler/src/test/java/dagger/internal/codegen/InaccessibleTypeTest.java b/compiler/src/test/java/dagger/internal/codegen/InaccessibleTypeTest.java index df427c5a591..07ce587c5d5 100644 --- a/compiler/src/test/java/dagger/internal/codegen/InaccessibleTypeTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/InaccessibleTypeTest.java @@ -74,65 +74,71 @@ public class InaccessibleTypeTest { "interface TestComponent {", " PublicClass publicClass();", "}"); - JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.DaggerTestComponent", - "package test;", - "", - "import foreign.NoDepClass_Factory;", - "import foreign.NonPublicClass1_Factory;", - "import foreign.NonPublicClass2_Factory;", - "import foreign.PublicClass;", - "import foreign.PublicClass_Factory;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class DaggerTestComponent implements TestComponent {", - " @SuppressWarnings(\"rawtypes\")", - " private Provider nonPublicClass1Provider;", - " @SuppressWarnings(\"rawtypes\")", - " private Provider nonPublicClass2Provider;", - " private Provider publicClassProvider;", - "", - " private DaggerTestComponent(Builder builder) {", - " assert builder != null;", - " initialize(builder);", - " }", - "", - " public static Builder builder() {", - " return new Builder();", - " }", - "", - " public static TestComponent create() {", - " return builder().build();", - " }", - "", - " @SuppressWarnings(\"unchecked\")", - " private void initialize(final Builder builder) {", - " this.nonPublicClass1Provider =", - " NonPublicClass1_Factory.create(NoDepClass_Factory.create());", - " this.nonPublicClass2Provider =", - " NonPublicClass2_Factory.create(NoDepClass_Factory.create());", - " this.publicClassProvider = PublicClass_Factory.create(", - " nonPublicClass1Provider,", - " nonPublicClass2Provider,", - " NoDepClass_Factory.create());", - " }", - "", - " @Override", - " public PublicClass publicClass() {", - " return publicClassProvider.get();", - " }", - "", - " public static final class Builder {", - " private Builder() {", - " }", - "", - " public TestComponent build() {", - " return new DaggerTestComponent(this);", - " }", - " }", - "}"); + JavaFileObject generatedComponent = + JavaFileObjects.forSourceLines( + "test.DaggerTestComponent", + "package test;", + "", + "import foreign.NoDepClass_Factory;", + "import foreign.NonPublicClass1_Factory;", + "import foreign.NonPublicClass2_Factory;", + "import foreign.PublicClass;", + "import foreign.PublicClass_Factory;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class DaggerTestComponent implements TestComponent {", + " @SuppressWarnings(\"rawtypes\")", + " private Provider nonPublicClass1Provider;", + " @SuppressWarnings(\"rawtypes\")", + " private Provider nonPublicClass2Provider;", + " private Provider publicClassProvider;", + "", + " private DaggerTestComponent(Builder builder) {", + " assert builder != null;", + " initialize(builder);", + " }", + "", + " public static Builder builder() {", + " return new Builder();", + " }", + "", + " public static TestComponent create() {", + " return builder().build();", + " }", + "", + " @SuppressWarnings(\"unchecked\")", + " private void initialize(final Builder builder) {", + " this.nonPublicClass1Provider =", + " NonPublicClass1_Factory.create(NoDepClass_Factory.create());", + " this.nonPublicClass2Provider =", + " NonPublicClass2_Factory.create(NoDepClass_Factory.create());", + " this.publicClassProvider = PublicClass_Factory.create(", + " nonPublicClass1Provider,", + " nonPublicClass2Provider,", + " NoDepClass_Factory.create());", + " }", + "", + " @Override", + " public PublicClass publicClass() {", + " return PublicClass_Factory.newPublicClass(", + " NonPublicClass1_Factory.newNonPublicClass1(", + " NoDepClass_Factory.newNoDepClass()),", + " NonPublicClass2_Factory.newNonPublicClass2(", + " NoDepClass_Factory.newNoDepClass()),", + " NoDepClass_Factory.newNoDepClass());", + " }", + "", + " public static final class Builder {", + " private Builder() {", + " }", + "", + " public TestComponent build() {", + " return new DaggerTestComponent(this);", + " }", + " }", + "}"); assertAbout(javaSources()) .that(ImmutableList.of( noDepClassFile, diff --git a/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java index a23a5008ba8..bf557bdc828 100644 --- a/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java @@ -132,31 +132,37 @@ public final class InjectConstructorFactoryGeneratorTest { "class GenericClass {", " @Inject GenericClass(T t) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class GenericClass_Factory implements Factory> {", - " private final Provider tProvider;", - "", - " public GenericClass_Factory(Provider tProvider) {", - " assert tProvider != null;", - " this.tProvider = tProvider;", - " }", - "", - " @Override", - " public GenericClass get() {", - " return new GenericClass(tProvider.get());", - " }", - "", - " public static Factory> create(Provider tProvider) {", - " return new GenericClass_Factory(tProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.GenericClass_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class GenericClass_Factory implements Factory> {", + " private final Provider tProvider;", + "", + " public GenericClass_Factory(Provider tProvider) {", + " assert tProvider != null;", + " this.tProvider = tProvider;", + " }", + "", + " @Override", + " public GenericClass get() {", + " return new GenericClass(tProvider.get());", + " }", + "", + " public static Factory> create(Provider tProvider) {", + " return new GenericClass_Factory(tProvider);", + " }", + "", + " public static GenericClass newGenericClass(T t) {", + " return new GenericClass(t);", + " }", + "}"); assertAbout(javaSource()).that(file) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -245,6 +251,9 @@ public final class InjectConstructorFactoryGeneratorTest { " return (Factory) INSTANCE;", " }", "", + " public static GenericClass newGenericClass() {", + " return new GenericClass();", + " }", "}"); assertAbout(javaSource()).that(file) .processedWith(new ComponentProcessor()) @@ -261,35 +270,41 @@ public final class InjectConstructorFactoryGeneratorTest { "class GenericClass {", " @Inject GenericClass(A a, B b) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class GenericClass_Factory implements Factory> {", - " private final Provider aProvider;", - " private final Provider bProvider;", - "", - " public GenericClass_Factory(Provider aProvider, Provider bProvider) {", - " assert aProvider != null;", - " this.aProvider = aProvider;", - " assert bProvider != null;", - " this.bProvider = bProvider;", - " }", - "", - " @Override", - " public GenericClass get() {", - " return new GenericClass(aProvider.get(), bProvider.get());", - " }", - "", - " public static Factory> create(", - " Provider aProvider, Provider bProvider) {", - " return new GenericClass_Factory(aProvider, bProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.GenericClass_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class GenericClass_Factory implements Factory> {", + " private final Provider aProvider;", + " private final Provider bProvider;", + "", + " public GenericClass_Factory(Provider aProvider, Provider bProvider) {", + " assert aProvider != null;", + " this.aProvider = aProvider;", + " assert bProvider != null;", + " this.bProvider = bProvider;", + " }", + "", + " @Override", + " public GenericClass get() {", + " return new GenericClass(aProvider.get(), bProvider.get());", + " }", + "", + " public static Factory> create(", + " Provider aProvider, Provider bProvider) {", + " return new GenericClass_Factory(aProvider, bProvider);", + " }", + "", + " public static GenericClass newGenericClass(A a, B b) {", + " return new GenericClass(a, b);", + " }", + "}"); assertAbout(javaSource()).that(file) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -308,46 +323,57 @@ public final class InjectConstructorFactoryGeneratorTest { " C extends List> {", " @Inject GenericClass(A a, B b, C c) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import java.util.List;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class GenericClass_Factory,", - " B extends List,", - " C extends List>", - " implements Factory> {", - " private final Provider aProvider;", - " private final Provider bProvider;", - " private final Provider cProvider;", - "", - " public GenericClass_Factory(Provider aProvider,", - " Provider bProvider,", - " Provider cProvider) {", - " assert aProvider != null;", - " this.aProvider = aProvider;", - " assert bProvider != null;", - " this.bProvider = bProvider;", - " assert cProvider != null;", - " this.cProvider = cProvider;", - " }", - "", - " @Override", - " public GenericClass get() {", - " return new GenericClass(aProvider.get(), bProvider.get(), cProvider.get());", - " }", - "", - " public static ,", - " B extends List,", - " C extends List> Factory> create(", - " Provider aProvider, Provider bProvider, Provider cProvider) {", - " return new GenericClass_Factory(aProvider, bProvider, cProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.GenericClass_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import java.util.List;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class GenericClass_Factory,", + " B extends List,", + " C extends List>", + " implements Factory> {", + " private final Provider aProvider;", + " private final Provider bProvider;", + " private final Provider cProvider;", + "", + " public GenericClass_Factory(Provider aProvider,", + " Provider bProvider,", + " Provider cProvider) {", + " assert aProvider != null;", + " this.aProvider = aProvider;", + " assert bProvider != null;", + " this.bProvider = bProvider;", + " assert cProvider != null;", + " this.cProvider = cProvider;", + " }", + "", + " @Override", + " public GenericClass get() {", + " return new GenericClass(", + " aProvider.get(), bProvider.get(), cProvider.get());", + " }", + "", + " public static ,", + " B extends List,", + " C extends List> Factory> create(", + " Provider aProvider, Provider bProvider, Provider cProvider) {", + " return new GenericClass_Factory(aProvider, bProvider, cProvider);", + " }", + "", + " public static <", + " A extends Number & Comparable,", + " B extends List,", + " C extends List>", + " GenericClass newGenericClass(A a, B b, C c) {", + " return new GenericClass(a, b, c);", + " }", + "}"); assertAbout(javaSource()).that(file) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -373,13 +399,15 @@ public final class InjectConstructorFactoryGeneratorTest { "test.GenericClass_Factory", "package test;", "", + "import dagger.Lazy;", "import dagger.internal.DoubleCheck;", "import dagger.internal.Factory;", "import javax.annotation.Generated;", "import javax.inject.Provider;", "", GENERATED_ANNOTATION, - "public final class GenericClass_Factory implements Factory> {", + "public final class GenericClass_Factory", + " implements Factory> {", " private final Provider aAndA2AndPaAndLaProvider;", " private final Provider qaProvider;", " private final Provider sAndS2AndPsAndLsProvider;", @@ -442,6 +470,26 @@ public final class InjectConstructorFactoryGeneratorTest { " bAndB2AndPbAndLbProvider,", " qbProvider);", " }", + "", + " public static GenericClass newGenericClass(", + " A a,", + " A a2,", + " Provider pa,", + " A qa,", + " Lazy la,", + " String s,", + " String s2,", + " Provider ps,", + " String qs,", + " Lazy ls,", + " B b,", + " B b2,", + " Provider pb,", + " B qb,", + " Lazy lb) {", + " return new GenericClass(", + " a, a2, pa, qa, la, s, s2, ps, qs, ls, b, b2, pb, qb, lb);", + " }", "}"); assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A)) .processedWith(new ComponentProcessor()) @@ -924,33 +972,38 @@ public final class InjectConstructorFactoryGeneratorTest { "class InjectConstructor {", " @Inject InjectConstructor(String s) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines( - "test.InjectConstructor_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class InjectConstructor_Factory ", - " implements Factory {", - "", - " private final Provider sProvider;", - "", - " public InjectConstructor_Factory(Provider sProvider) {", - " assert sProvider != null;", - " this.sProvider = sProvider;", - " }", - "", - " @Override public InjectConstructor get() {", - " return new InjectConstructor(sProvider.get());", - " }", - "", - " public static Factory create(Provider sProvider) {", - " return new InjectConstructor_Factory(sProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.InjectConstructor_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class InjectConstructor_Factory ", + " implements Factory {", + "", + " private final Provider sProvider;", + "", + " public InjectConstructor_Factory(Provider sProvider) {", + " assert sProvider != null;", + " this.sProvider = sProvider;", + " }", + "", + " @Override public InjectConstructor get() {", + " return new InjectConstructor(sProvider.get());", + " }", + "", + " public static Factory create(Provider sProvider) {", + " return new InjectConstructor_Factory(sProvider);", + " }", + "", + " public static InjectConstructor newInjectConstructor(String s) {", + " return new InjectConstructor(s);", + " }", + "}"); assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor()) .compilesWithoutError() .and().generatesSources(expected); @@ -1069,35 +1122,40 @@ public void wildcardDependency() { "class InjectConstructor {", " @Inject InjectConstructor(List objects) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines( - "test.InjectConstructor_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import java.util.List;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class InjectConstructor_Factory ", - " implements Factory {", - "", - " private final Provider> objectsProvider;", - "", - " public InjectConstructor_Factory(Provider> objectsProvider) {", - " assert objectsProvider != null;", - " this.objectsProvider = objectsProvider;", - " }", - "", - " @Override public InjectConstructor get() {", - " return new InjectConstructor(objectsProvider.get());", - " }", - "", - " public static Factory create(", - " Provider> objectsProvider) {", - " return new InjectConstructor_Factory(objectsProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.InjectConstructor_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import java.util.List;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class InjectConstructor_Factory ", + " implements Factory {", + "", + " private final Provider> objectsProvider;", + "", + " public InjectConstructor_Factory(Provider> objectsProvider) {", + " assert objectsProvider != null;", + " this.objectsProvider = objectsProvider;", + " }", + "", + " @Override public InjectConstructor get() {", + " return new InjectConstructor(objectsProvider.get());", + " }", + "", + " public static Factory create(", + " Provider> objectsProvider) {", + " return new InjectConstructor_Factory(objectsProvider);", + " }", + "", + " public static InjectConstructor newInjectConstructor(List objects) {", + " return new InjectConstructor(objects);", + " }", + "}"); assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor()) .compilesWithoutError() .and().generatesSources(expected); @@ -1118,34 +1176,39 @@ public void basicNameCollision() { "class InjectConstructor {", " @Inject InjectConstructor(Factory factory) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines( - "test.InjectConstructor_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class InjectConstructor_Factory ", - " implements Factory {", - "", - " private final Provider factoryProvider;", - "", - " public InjectConstructor_Factory(Provider factoryProvider) {", - " assert factoryProvider != null;", - " this.factoryProvider = factoryProvider;", - " }", - "", - " @Override public InjectConstructor get() {", - " return new InjectConstructor(factoryProvider.get());", - " }", - "", - " public static Factory create(", - " Provider factoryProvider) {", - " return new InjectConstructor_Factory(factoryProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.InjectConstructor_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class InjectConstructor_Factory ", + " implements Factory {", + "", + " private final Provider factoryProvider;", + "", + " public InjectConstructor_Factory(Provider factoryProvider) {", + " assert factoryProvider != null;", + " this.factoryProvider = factoryProvider;", + " }", + "", + " @Override public InjectConstructor get() {", + " return new InjectConstructor(factoryProvider.get());", + " }", + "", + " public static Factory create(", + " Provider factoryProvider) {", + " return new InjectConstructor_Factory(factoryProvider);", + " }", + "", + " public static InjectConstructor newInjectConstructor(other.pkg.Factory factory) {", + " return new InjectConstructor(factory);", + " }", + "}"); assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file)) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -1169,35 +1232,40 @@ public void nestedNameCollision() { "class InjectConstructor {", " @Inject InjectConstructor(Outer.Factory factory) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines( - "test.InjectConstructor_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "import other.pkg.Outer;", - "", - GENERATED_ANNOTATION, - "public final class InjectConstructor_Factory ", - " implements Factory {", - "", - " private final Provider factoryProvider;", - "", - " public InjectConstructor_Factory(Provider factoryProvider) {", - " assert factoryProvider != null;", - " this.factoryProvider = factoryProvider;", - " }", - "", - " @Override public InjectConstructor get() {", - " return new InjectConstructor(factoryProvider.get());", - " }", - "", - " public static Factory create(", - " Provider factoryProvider) {", - " return new InjectConstructor_Factory(factoryProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.InjectConstructor_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "import other.pkg.Outer;", + "", + GENERATED_ANNOTATION, + "public final class InjectConstructor_Factory ", + " implements Factory {", + "", + " private final Provider factoryProvider;", + "", + " public InjectConstructor_Factory(Provider factoryProvider) {", + " assert factoryProvider != null;", + " this.factoryProvider = factoryProvider;", + " }", + "", + " @Override public InjectConstructor get() {", + " return new InjectConstructor(factoryProvider.get());", + " }", + "", + " public static Factory create(", + " Provider factoryProvider) {", + " return new InjectConstructor_Factory(factoryProvider);", + " }", + "", + " public static InjectConstructor newInjectConstructor(Outer.Factory factory) {", + " return new InjectConstructor(factory);", + " }", + "}"); assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file)) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -1223,39 +1291,47 @@ public void samePackageNameCollision() { "class InjectConstructor implements CommonName {", " @Inject InjectConstructor(other.pkg.CommonName otherPackage, CommonName samePackage) {}", "}"); - JavaFileObject expected = JavaFileObjects.forSourceLines( - "test.InjectConstructor_Factory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class InjectConstructor_Factory ", - " implements Factory {", - "", - " private final Provider otherPackageProvider;", - " private final Provider samePackageProvider;", - "", - " public InjectConstructor_Factory(Provider otherPackageProvider,", - " Provider samePackageProvider) {", - " assert otherPackageProvider != null;", - " this.otherPackageProvider = otherPackageProvider;", - " assert samePackageProvider != null;", - " this.samePackageProvider = samePackageProvider;", - " }", - "", - " @Override public InjectConstructor get() {", - " return new InjectConstructor(otherPackageProvider.get(), samePackageProvider.get());", - " }", - "", - " public static Factory create(", - " Provider otherPackageProvider,", - " Provider samePackageProvider) {", - " return new InjectConstructor_Factory(otherPackageProvider, samePackageProvider);", - " }", - "}"); + JavaFileObject expected = + JavaFileObjects.forSourceLines( + "test.InjectConstructor_Factory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class InjectConstructor_Factory ", + " implements Factory {", + "", + " private final Provider otherPackageProvider;", + " private final Provider samePackageProvider;", + "", + " public InjectConstructor_Factory(", + " Provider otherPackageProvider,", + " Provider samePackageProvider) {", + " assert otherPackageProvider != null;", + " this.otherPackageProvider = otherPackageProvider;", + " assert samePackageProvider != null;", + " this.samePackageProvider = samePackageProvider;", + " }", + "", + " @Override public InjectConstructor get() {", + " return new InjectConstructor(", + " otherPackageProvider.get(), samePackageProvider.get());", + " }", + "", + " public static Factory create(", + " Provider otherPackageProvider,", + " Provider samePackageProvider) {", + " return new InjectConstructor_Factory(otherPackageProvider, samePackageProvider);", + " }", + "", + " public static InjectConstructor newInjectConstructor(", + " other.pkg.CommonName otherPackage, CommonName samePackage) {", + " return new InjectConstructor(otherPackage, samePackage);", + " }", + "}"); assertAbout(javaSources()) .that(ImmutableList.of(samePackageInterface, differentPackageInterface, file)) .processedWith(new ComponentProcessor()) @@ -1292,6 +1368,10 @@ public void noDeps() { " public static Factory create() {", " return INSTANCE;", " }", + "", + " public static SimpleType newSimpleType() {", + " return new SimpleType();", + " }", "}"); assertAbout(javaSource()) .that(simpleType) @@ -1338,6 +1418,10 @@ public void noDeps() { " public static Factory create() {", " return INSTANCE;", " }", + "", + " public static OuterType.A newA() {", + " return new OuterType.A();", + " }", "}"); assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile)) .processedWith(new ComponentProcessor()) diff --git a/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java index 202c8c485a0..8d02a499c6d 100644 --- a/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java @@ -247,30 +247,36 @@ public void providesMethodReturnsProduced() { " return \"\";", " }", "}"); - JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import dagger.internal.Preconditions;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class TestModule_ProvideStringFactory implements Factory {", - " private final TestModule module;", - "", - " public TestModule_ProvideStringFactory(TestModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override public String get() {", - " return Preconditions.checkNotNull(module.provideString(), " + NPE_LITERAL + ");", - " }", - "", - " public static Factory create(TestModule module) {", - " return new TestModule_ProvideStringFactory(module);", - " }", - "}"); + JavaFileObject factoryFile = + JavaFileObjects.forSourceLines( + "TestModule_ProvideStringFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import dagger.internal.Preconditions;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class TestModule_ProvideStringFactory implements Factory {", + " private final TestModule module;", + "", + " public TestModule_ProvideStringFactory(TestModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override public String get() {", + " return Preconditions.checkNotNull(module.provideString(), " + NPE_LITERAL + ");", + " }", + "", + " public static Factory create(TestModule module) {", + " return new TestModule_ProvideStringFactory(module);", + " }", + "", + " public static String proxyProvideString(TestModule instance) {", + " return instance.provideString();", + " }", + "}"); assertAbout(javaSource()).that(moduleFile) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -290,29 +296,35 @@ public void providesMethodReturnsProduced() { " return \"\";", " }", "}"); - JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class TestModule_ProvideStringFactory implements Factory {", - " private final TestModule module;", - "", - " public TestModule_ProvideStringFactory(TestModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override public String get() {", - " return module.provideString();", - " }", - "", - " public static Factory create(TestModule module) {", - " return new TestModule_ProvideStringFactory(module);", - " }", - "}"); + JavaFileObject factoryFile = + JavaFileObjects.forSourceLines( + "TestModule_ProvideStringFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class TestModule_ProvideStringFactory implements Factory {", + " private final TestModule module;", + "", + " public TestModule_ProvideStringFactory(TestModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override public String get() {", + " return module.provideString();", + " }", + "", + " public static Factory create(TestModule module) {", + " return new TestModule_ProvideStringFactory(module);", + " }", + "", + " public static String proxyProvideString(TestModule instance) {", + " return instance.provideString();", + " }", + "}"); assertAbout(javaSource()).that(moduleFile) .withCompilerOptions("-Adagger.nullableValidation=WARNING") .processedWith(new ComponentProcessor()) @@ -331,31 +343,37 @@ public void providesMethodReturnsProduced() { "final class TestModule {", " @Provides @Nullable String provideString() { return null; }", "}"); - JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class TestModule_ProvideStringFactory implements Factory {", - " private final TestModule module;", - "", - " public TestModule_ProvideStringFactory(TestModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override", - " @Nullable", - " public String get() {", - " return module.provideString();", - " }", - "", - " public static Factory create(TestModule module) {", - " return new TestModule_ProvideStringFactory(module);", - " }", - "}"); + JavaFileObject factoryFile = + JavaFileObjects.forSourceLines( + "TestModule_ProvideStringFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class TestModule_ProvideStringFactory implements Factory {", + " private final TestModule module;", + "", + " public TestModule_ProvideStringFactory(TestModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override", + " @Nullable", + " public String get() {", + " return module.provideString();", + " }", + "", + " public static Factory create(TestModule module) {", + " return new TestModule_ProvideStringFactory(module);", + " }", + "", + " public static String proxyProvideString(TestModule instance) {", + " return instance.provideString();", + " }", + "}"); assertAbout(javaSources()).that(ImmutableList.of(moduleFile, NULLABLE)) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -410,54 +428,61 @@ public void providesMethodReturnsProduced() { " return new Object();", " }", "}"); - JavaFileObject listFactoryFile = JavaFileObjects.forSourceLines( - "TestModule_ProvideObjectsFactory", - "package test;", - "", - "import dagger.MembersInjector;", - "import dagger.internal.Factory;", - "import dagger.internal.Preconditions;", - "import java.util.List;", - "import javax.annotation.Generated;", - "import javax.inject.Provider;", - "", - GENERATED_ANNOTATION, - "public final class TestModule_ProvideObjectsFactory implements Factory> {", - " private final TestModule module;", - " private final Provider aProvider;", - " private final Provider bProvider;", - " private final MembersInjector xMembersInjector;", - "", - " public TestModule_ProvideObjectsFactory(", - " TestModule module,", - " Provider aProvider,", - " Provider bProvider,", - " MembersInjector xMembersInjector) {", - " assert module != null;", - " this.module = module;", - " assert aProvider != null;", - " this.aProvider = aProvider;", - " assert bProvider != null;", - " this.bProvider = bProvider;", - " assert xMembersInjector != null;", - " this.xMembersInjector = xMembersInjector;", - " }", - "", - " @Override public List get() {", - " return Preconditions.checkNotNull(", - " module.provideObjects(aProvider.get(), bProvider.get(), xMembersInjector),", - " " + NPE_LITERAL + ");", - " }", - "", - " public static Factory> create(", - " TestModule module,", - " Provider aProvider,", - " Provider bProvider,", - " MembersInjector xMembersInjector) {", - " return new TestModule_ProvideObjectsFactory(", - " module, aProvider, bProvider, xMembersInjector);", - " }", - "}"); + JavaFileObject listFactoryFile = + JavaFileObjects.forSourceLines( + "TestModule_ProvideObjectsFactory", + "package test;", + "", + "import dagger.MembersInjector;", + "import dagger.internal.Factory;", + "import dagger.internal.Preconditions;", + "import java.util.List;", + "import javax.annotation.Generated;", + "import javax.inject.Provider;", + "", + GENERATED_ANNOTATION, + "public final class TestModule_ProvideObjectsFactory", + " implements Factory> {", + " private final TestModule module;", + " private final Provider aProvider;", + " private final Provider bProvider;", + " private final MembersInjector xMembersInjector;", + "", + " public TestModule_ProvideObjectsFactory(", + " TestModule module,", + " Provider aProvider,", + " Provider bProvider,", + " MembersInjector xMembersInjector) {", + " assert module != null;", + " this.module = module;", + " assert aProvider != null;", + " this.aProvider = aProvider;", + " assert bProvider != null;", + " this.bProvider = bProvider;", + " assert xMembersInjector != null;", + " this.xMembersInjector = xMembersInjector;", + " }", + "", + " @Override public List get() {", + " return Preconditions.checkNotNull(", + " module.provideObjects(aProvider.get(), bProvider.get(), xMembersInjector),", + " " + NPE_LITERAL + ");", + " }", + "", + " public static Factory> create(", + " TestModule module,", + " Provider aProvider,", + " Provider bProvider,", + " MembersInjector xMembersInjector) {", + " return new TestModule_ProvideObjectsFactory(", + " module, aProvider, bProvider, xMembersInjector);", + " }", + "", + " public static List proxyProvideObjects(", + " TestModule instance, Object a, Object b, Object x) {", + " return instance.provideObjects(a, b, (MembersInjector) x);", + " }", + "}"); assertAbout(javaSources()).that( ImmutableList.of(classXFile, moduleFile, QUALIFIER_A, QUALIFIER_B)) .processedWith(new ComponentProcessor()) @@ -480,30 +505,36 @@ public void providesMethodReturnsProduced() { " return \"\";", " }", "}"); - JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import dagger.internal.Preconditions;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class TestModule_ProvideStringFactory implements Factory {", - " private final TestModule module;", - "", - " public TestModule_ProvideStringFactory(TestModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override public String get() {", - " return Preconditions.checkNotNull(module.provideString(), " + NPE_LITERAL + ");", - " }", - "", - " public static Factory create(TestModule module) {", - " return new TestModule_ProvideStringFactory(module);", - " }", - "}"); + JavaFileObject factoryFile = + JavaFileObjects.forSourceLines( + "TestModule_ProvideStringFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import dagger.internal.Preconditions;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class TestModule_ProvideStringFactory implements Factory {", + " private final TestModule module;", + "", + " public TestModule_ProvideStringFactory(TestModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override public String get() {", + " return Preconditions.checkNotNull(module.provideString(), " + NPE_LITERAL + ");", + " }", + "", + " public static Factory create(TestModule module) {", + " return new TestModule_ProvideStringFactory(module);", + " }", + "", + " public static String proxyProvideString(TestModule instance) {", + " return instance.provideString();", + " }", + "}"); assertAbout(javaSource()).that(moduleFile) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -527,33 +558,40 @@ public void providesMethodReturnsProduced() { " return new ArrayList<>();", " }", "}"); - JavaFileObject factoryFile = JavaFileObjects.forSourceLines( - "TestModule_ProvideWildcardListFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import dagger.internal.Preconditions;", - "import java.util.List;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class TestModule_ProvideWildcardListFactory implements " - + "Factory>> {", - " private final TestModule module;", - "", - " public TestModule_ProvideWildcardListFactory(TestModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override public List> get() {", - " return Preconditions.checkNotNull(module.provideWildcardList(), " + NPE_LITERAL + ");", - " }", - "", - " public static Factory>> create(TestModule module) {", - " return new TestModule_ProvideWildcardListFactory(module);", - " }", - "}"); + JavaFileObject factoryFile = + JavaFileObjects.forSourceLines( + "TestModule_ProvideWildcardListFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import dagger.internal.Preconditions;", + "import java.util.List;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class TestModule_ProvideWildcardListFactory implements " + + "Factory>> {", + " private final TestModule module;", + "", + " public TestModule_ProvideWildcardListFactory(TestModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override public List> get() {", + " return Preconditions.checkNotNull(module.provideWildcardList(), " + + NPE_LITERAL + + ");", + " }", + "", + " public static Factory>> create(TestModule module) {", + " return new TestModule_ProvideWildcardListFactory(module);", + " }", + "", + " public static List> proxyProvideWildcardList(TestModule instance) {", + " return instance.provideWildcardList();", + " }", + "}"); assertAbout(javaSource()).that(moduleFile) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -575,31 +613,37 @@ public void providesMethodReturnsProduced() { " return null;", " }", "}"); - JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringsFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import dagger.internal.Preconditions;", - "import java.util.Set;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class TestModule_ProvideStringsFactory implements Factory> {", - " private final TestModule module;", - "", - " public TestModule_ProvideStringsFactory(TestModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override public Set get() {", - " return Preconditions.checkNotNull(module.provideStrings(), " + NPE_LITERAL + ");", - " }", - "", - " public static Factory> create(TestModule module) {", - " return new TestModule_ProvideStringsFactory(module);", - " }", - "}"); + JavaFileObject factoryFile = + JavaFileObjects.forSourceLines( + "TestModule_ProvideStringsFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import dagger.internal.Preconditions;", + "import java.util.Set;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class TestModule_ProvideStringsFactory implements Factory> {", + " private final TestModule module;", + "", + " public TestModule_ProvideStringsFactory(TestModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override public Set get() {", + " return Preconditions.checkNotNull(module.provideStrings(), " + NPE_LITERAL + ");", + " }", + "", + " public static Factory> create(TestModule module) {", + " return new TestModule_ProvideStringsFactory(module);", + " }", + "", + " public static Set proxyProvideStrings(TestModule instance) {", + " return instance.provideStrings();", + " }", + "}"); assertAbout(javaSource()).that(moduleFile) .processedWith(new ComponentProcessor()) .compilesWithoutError() @@ -892,6 +936,12 @@ public void genericSubclassedModule() { " Factory> create(ParentModule module, Provider bProvider) {", " return new ParentModule_ProvideListBFactory(module, bProvider);", " }", + "", + " public static > List", + " proxyProvideListB(", + " ParentModule instance, B b) {", + " return instance.provideListB(b);", + " }", "}"); JavaFileObject bElementFactory = JavaFileObjects.forSourceLines( @@ -927,6 +977,12 @@ public void genericSubclassedModule() { " Factory create(ParentModule module, Provider bProvider) {", " return new ParentModule_ProvideBElementFactory(module, bProvider);", " }", + "", + " public static >", + " B proxyProvideBElement(", + " ParentModule instance, B b) {", + " return instance.provideBElement(b);", + " }", "}"); JavaFileObject bEntryFactory = JavaFileObjects.forSourceLines( @@ -962,60 +1018,77 @@ public void genericSubclassedModule() { " Factory create(ParentModule module, Provider bProvider) {", " return new ParentModule_ProvideBEntryFactory(module, bProvider);", " }", + "", + " public static >", + " B proxyProvideBEntry(", + " ParentModule instance, B b) {", + " return instance.provideBEntry(b);", + " }", + "}"); + JavaFileObject numberFactory = + JavaFileObjects.forSourceLines( + "test.ChildNumberModule_ProvideNumberFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import dagger.internal.Preconditions;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class ChildNumberModule_ProvideNumberFactory", + " implements Factory {", + " private final ChildNumberModule module;", + "", + " public ChildNumberModule_ProvideNumberFactory(ChildNumberModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override", + " public Number get() { ", + " return Preconditions.checkNotNull(module.provideNumber(), " + NPE_LITERAL + ");", + " }", + "", + " public static Factory create(ChildNumberModule module) {", + " return new ChildNumberModule_ProvideNumberFactory(module);", + " }", + "", + " public static Number proxyProvideNumber(ChildNumberModule instance) {", + " return instance.provideNumber();", + " }", + "}"); + JavaFileObject integerFactory = + JavaFileObjects.forSourceLines( + "test.ChildIntegerModule_ProvideIntegerFactory", + "package test;", + "", + "import dagger.internal.Factory;", + "import dagger.internal.Preconditions;", + "import javax.annotation.Generated;", + "", + GENERATED_ANNOTATION, + "public final class ChildIntegerModule_ProvideIntegerFactory", + " implements Factory {", + " private final ChildIntegerModule module;", + "", + " public ChildIntegerModule_ProvideIntegerFactory(ChildIntegerModule module) {", + " assert module != null;", + " this.module = module;", + " }", + "", + " @Override", + " public Integer get() { ", + " return Preconditions.checkNotNull(module.provideInteger(), " + NPE_LITERAL + ");", + " }", + "", + " public static Factory create(ChildIntegerModule module) {", + " return new ChildIntegerModule_ProvideIntegerFactory(module);", + " }", + "", + " public static Integer proxyProvideInteger(ChildIntegerModule instance) {", + " return instance.provideInteger();", + " }", "}"); - JavaFileObject numberFactory = JavaFileObjects.forSourceLines( - "test.ChildNumberModule_ProvideNumberFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import dagger.internal.Preconditions;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class ChildNumberModule_ProvideNumberFactory implements Factory {", - " private final ChildNumberModule module;", - "", - " public ChildNumberModule_ProvideNumberFactory(ChildNumberModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override", - " public Number get() { ", - " return Preconditions.checkNotNull(module.provideNumber(), " + NPE_LITERAL + ");", - " }", - "", - " public static Factory create(ChildNumberModule module) {", - " return new ChildNumberModule_ProvideNumberFactory(module);", - " }", - "}"); - JavaFileObject integerFactory = JavaFileObjects.forSourceLines( - "test.ChildIntegerModule_ProvideIntegerFactory", - "package test;", - "", - "import dagger.internal.Factory;", - "import dagger.internal.Preconditions;", - "import javax.annotation.Generated;", - "", - GENERATED_ANNOTATION, - "public final class ChildIntegerModule_ProvideIntegerFactory", - " implements Factory {", - " private final ChildIntegerModule module;", - "", - " public ChildIntegerModule_ProvideIntegerFactory(ChildIntegerModule module) {", - " assert module != null;", - " this.module = module;", - " }", - "", - " @Override", - " public Integer get() { ", - " return Preconditions.checkNotNull(module.provideInteger(), " + NPE_LITERAL + ");", - " }", - "", - " public static Factory create(ChildIntegerModule module) {", - " return new ChildIntegerModule_ProvideIntegerFactory(module);", - " }", - "}"); assertAbout(javaSources()) .that(ImmutableList.of(parent, numberChild, integerChild, component)) .processedWith(new ComponentProcessor()) @@ -1081,6 +1154,10 @@ public void genericSubclassedModule() { " public static Factory> create() {", " return INSTANCE;", " }", + "", + " public static Map proxyProvideMapStringNumber() {", + " return ParameterizedModule.provideMapStringNumber();", + " }", "}"); JavaFileObject provideNonGenericTypeFactory = @@ -1107,6 +1184,10 @@ public void genericSubclassedModule() { " public static Factory create() {", " return INSTANCE;", " }", + "", + " public static Object proxyProvideNonGenericType() {", + " return ParameterizedModule.provideNonGenericType();", + " }", "}"); JavaFileObject provideNonGenericTypeWithDepsFactory = @@ -1140,6 +1221,10 @@ public void genericSubclassedModule() { " public static Factory create(Provider oProvider) {", " return new ParameterizedModule_ProvideNonGenericTypeWithDepsFactory(oProvider);", " }", + "", + " public static String proxyProvideNonGenericTypeWithDeps(Object o) {", + " return ParameterizedModule.provideNonGenericTypeWithDeps(o);", + " }", "}"); assertAbout(javaSource()) From 5abbc828bfccea349ce1734791b504f939c5b952 Mon Sep 17 00:00:00 2001 From: ronshapiro Date: Wed, 16 Nov 2016 11:17:28 -0800 Subject: [PATCH 3/3] Fix dagger-android build in Travis ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=139355153 --- .travis.yml | 14 ++++++++++---- android/pom.xml | 2 +- examples/pom.xml | 2 +- pom.xml | 1 + 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 29f9ff33f05..44bfc7c4e85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,12 @@ jdk: android: components: - - build-tools-23.0.0 - - android-23 - licenses: - - android-sdk-license-5be876d5 + - tools + - tools # Duplicated as per https://github.com/travis-ci/travis-ci/issues/6040#issuecomment-219367943 + - build-tools-25.0.0 + - android-25 + - platform-tools + - extra-android-m2repository before_install: - sudo rm -f /etc/mavenrc @@ -38,3 +40,7 @@ branches: only: - master - /^release.*$/ + +cache: + directories: + - $HOME/.m2 diff --git a/android/pom.xml b/android/pom.xml index 0402608c5b8..03ab262a9e5 100644 --- a/android/pom.xml +++ b/android/pom.xml @@ -69,7 +69,7 @@ true - 24 + ${android.latest.version} ${env.ANDROID_HOME} diff --git a/examples/pom.xml b/examples/pom.xml index 1985ff3dbcc..95406ea8f57 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -77,7 +77,7 @@ 4.3.0 - 23 + ${android.latest.version} ${env.ANDROID_HOME} diff --git a/pom.xml b/pom.xml index 04f0ebd7fbd..b3d76d3a348 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,7 @@ UTF-8 24.2.0 + 25