Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.30] NoSuchElementException in KotlinMetadata.java #2190

Closed
tadfisher opened this issue Nov 20, 2020 · 10 comments · Fixed by #2193
Closed

[2.30] NoSuchElementException in KotlinMetadata.java #2190

tadfisher opened this issue Nov 20, 2020 · 10 comments · Fixed by #2193

Comments

@tadfisher
Copy link

Since updating to 2.30, compiling is failing during the kapt step. Here's the bottom of the stacktrace. Unfortunately I can't tell from this error where the problem occurs.

Caused by: java.util.NoSuchElementException
	at dagger.internal.codegen.extension.DaggerCollectors$ToOptionalState.getElement(DaggerCollectors.java:145)
	at dagger.internal.codegen.extension.DaggerCollectors.lambda$static$1(DaggerCollectors.java:61)
	at dagger.internal.codegen.kotlin.KotlinMetadata.findProperty(KotlinMetadata.java:260)
	at dagger.internal.codegen.kotlin.KotlinMetadata.lambda$mapFieldToAnnotationMethod$8(KotlinMetadata.java:226)
	at dagger.internal.codegen.kotlin.KotlinMetadata.mapFieldToAnnotationMethod(KotlinMetadata.java:222)
	at dagger.internal.codegen.kotlin.KotlinMetadata.lambda$new$4(KotlinMetadata.java:122)
	at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers.java:167)
	at dagger.internal.codegen.kotlin.KotlinMetadata.isMissingSyntheticAnnotationMethod(KotlinMetadata.java:321)
	at dagger.internal.codegen.kotlin.KotlinMetadataUtil.isMissingSyntheticPropertyForAnnotations(KotlinMetadataUtil.java:77)
	at dagger.internal.codegen.validation.DependencyRequestValidator.checkQualifiers(DependencyRequestValidator.java:77)
	at dagger.internal.codegen.validation.DependencyRequestValidator.validateDependencyRequest(DependencyRequestValidator.java:68)
	at dagger.internal.codegen.validation.InjectValidator.validateDependencyRequest(InjectValidator.java:256)
	at dagger.internal.codegen.validation.InjectValidator.validateField(InjectValidator.java:212)
	at dagger.internal.codegen.validation.InjectValidator.validateMembersInjectionType(InjectValidator.java:268)
	at dagger.internal.codegen.validation.InjectBindingRegistryImpl.tryRegisterMembersInjectedType(InjectBindingRegistryImpl.java:281)
	at dagger.internal.codegen.validation.InjectBindingRegistryImpl.tryRegisterMembersInjectedType(InjectBindingRegistryImpl.java:265)
	at dagger.internal.codegen.InjectProcessingStep$1.visitVariableAsField(InjectProcessingStep.java:54)
	at dagger.internal.codegen.InjectProcessingStep$1.visitVariableAsField(InjectProcessingStep.java:44)
	at jdk.compiler/com.sun.tools.javac.code.Symbol$VarSymbol.accept(Symbol.java:1576)
	at dagger.internal.codegen.InjectProcessingStep.process(InjectProcessingStep.java:76)
	at dagger.internal.codegen.validation.TypeCheckingProcessingStep.lambda$process$0(TypeCheckingProcessingStep.java:51)
	at com.google.common.collect.RegularImmutableMap.forEach(RegularImmutableMap.java:185)
	at dagger.internal.codegen.validation.TypeCheckingProcessingStep.process(TypeCheckingProcessingStep.java:48)
	at dagger.internal.codegen.validation.TypeCheckingProcessingStep.process(TypeCheckingProcessingStep.java:34)
	at dagger.shaded.auto.common.BasicAnnotationProcessor$ProcessingStepAsStep.process(BasicAnnotationProcessor.java:495)
	at dagger.shaded.auto.common.BasicAnnotationProcessor.process(BasicAnnotationProcessor.java:228)
	at dagger.shaded.auto.common.BasicAnnotationProcessor.process(BasicAnnotationProcessor.java:208)
	at org.jetbrains.kotlin.kapt3.base.incremental.IncrementalProcessor.process(incrementalProcessors.kt)
	at org.jetbrains.kotlin.kapt3.base.ProcessorWrapper.process(annotationProcessing.kt:161)
	at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:980)
	... 42 more
@Hospes
Copy link

Hospes commented Nov 20, 2020

The same for me

@danysantiago
Copy link
Member

Thanks for reporting this.

What Kotlin version are you on? Do you also happen to have KAPT's correctErrorType turned ON?

The likely cause of this issue is a 'weird' (possibly a delegate) property in a member injected class for which its type is generated. Something like this:

class MyMemberInjectedClass {
  @Inject lateinit var foo: Foo
  val delegateProperty: GeneratedType by ...
}

For these cases we have a workaround to a KAPT bug that seems to not be working for all cases: https://github.com/google/dagger/blob/master/java/dagger/internal/codegen/kotlin/KotlinMetadata.java#L257

We might need a bit more time to hunt this issue down, I don't think we'll have a patch release until next week, sorry.

@tadfisher
Copy link
Author

We are on Kotlin 1.4.10. We do have correctErrorTypes enabled, along with the following options:

correctErrorTypes = true
mapDiagnosticLocations = true
useBuildCache = true
kapt.include.compile.classpath=false

I will try with correctErrorTypes off.

@danysantiago
Copy link
Member

This is a bit of a stretch too but you can find out the class with the 'faulty' property if you attach a debugger, (we really need to publish instructions on how to do this), but basically you run a very big Gradle command:

./gradlew clean app:kaptDebugKotlin --no-daemon -Dorg.gradle.debug=true -Dkotlin.compiler.execution.strategy="in-process" -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket\,address=5005\,server=y\,suspend=n"

Then in the IDE add a new run configuration of the 'Remote' category and when the command above start click the 'attach debug' icon. There are more instructions (with screenshots) in this comment.

If you put a non-suspending breakpoint in findProperty() that logs the type element (the class) being processed it can help us track down the Kotlin code that might be causing this.

@tadfisher
Copy link
Author

Same stack trace with correctErrorTypes = false. I'll try running the debugger.

@kozaxinan
Copy link

kozaxinan commented Nov 21, 2020

Hi, I wasn't able to debug but I found which class causes the problem for us. With debug mode, I also verified problem is coming from an Activity class.

In our activity, we inject ViewModelFactory

@Inject internal lateinit var factory: ViewModelFactory<AbcViewModel>

Factory is used in a by viewModel delegation but removing delegation didn't have any effect.

Without ViewModelFactory<> injection, dagger doesn't throw NoSuchElementException.

ViewModelFactory class

class ViewModelFactory<out T : ViewModel> @Inject constructor(
  private val provider: Provider<T>
) : ViewModelProvider.Factory {

  @Suppress("UNCHECKED_CAST")
  override fun <T : ViewModel> create(modelClass: Class<T>): T = try {
    provider.get() as T
  } catch (cause: ClassCastException) {
    throw IllegalStateException(
      "Class ${modelClass.name} is not supported by this factory",
      cause
    )
  }
}

@danysantiago
Copy link
Member

By any chance do you use Kotlin's Android extensions (apply plugin: 'kotlin-android-extensions')?

@kozaxinan
Copy link

Yes, our module has kotlin-android-extension. I noticed that in that module, we didnt setup Kotlin extensions just for parcelizer.
After adding androidExtensions { features = ['parcelize'] }, build finished without NoSuchElementException.

@GuilhE
Copy link

GuilhE commented Nov 23, 2020

Yes, our module has kotlin-android-extension. I noticed that in that module, we didnt setup Kotlin extensions just for parcelizer.
After adding androidExtensions { features = ['parcelize'] }, build finished without NoSuchElementException.

I'll complement this answer with androidExtensions .kts version:

androidExtensions {
    features = mutableSetOf("parcelize")
}

Just a small not also:
Warning: The 'kotlin-android-extensions' Gradle plugin is deprecated. Please use this migration guide (https://goo.gle/kotlin-android-extensions-deprecation) to start working with View Binding (https://developer.android.com/topic/libraries/view-binding) and the 'kotlin-parcelize' plugin.

@sczerwinski
Copy link

sczerwinski commented Nov 23, 2020

I'm using kotlin-android-extension plugin for getting views from layouts. So in my case, setting androidExtensions { features = ['parcelize'] } only "helped" for :app:kaptDebugKotlin, but now I'm getting errors in :app:compileDebugKotlin: Unresolved reference: synthetic.

When I set androidExtensions { features = ['views'] } instead, java.util.NoSuchElementException is back.

The error was not there in Dagger 2.29.1, it's just in 2.30.

I tried debugging, but no luck getting any additional information so far.

EDIT: Just saw @GuilhE's answer. Will try that out.

EDIT2: Replacing kotlin-android-extension with View Binding works.

copybara-service bot pushed a commit that referenced this issue Nov 23, 2020
Dagger matches fields with Kotlin property metadata to generate code that uses property getter methods and/or retrieve qualifier annotations. This CL makes it so that the matching is done lazily and only on fields Dagger is interested on (annotated with @Inject, @BindValue, etc) instead of attempting to match all fields of the TypeElement being processed. This makes it so that the strict requirement of a fields having property metadata is only enforced on relevant fields and other fields, such as those generated by compiler extensions and without metadata get ignored.

Fixes: #2190
RELNOTES=Fix a bug where Dagger was unnecessarily inspecting all fields of a class and attempting to find their Kotlin metadata, failing to do so sometimes and crashing the processor.
PiperOrigin-RevId: 343674753
copybara-service bot pushed a commit that referenced this issue Nov 23, 2020
Dagger matches fields with Kotlin property metadata to generate code that uses property getter methods and/or retrieve qualifier annotations. This CL makes it so that the matching is done lazily and only on fields Dagger is interested on (annotated with @Inject, @BindValue, etc) instead of attempting to match all fields of the TypeElement being processed. This makes it so that the strict requirement of a fields having property metadata is only enforced on relevant fields and other fields, such as those generated by compiler extensions and without metadata get ignored.

Fixes: #2190
RELNOTES=Fix a bug where Dagger was unnecessarily inspecting all fields of a class and attempting to find their Kotlin metadata, failing to do so sometimes and crashing the processor.
PiperOrigin-RevId: 343674753
copybara-service bot pushed a commit that referenced this issue Nov 23, 2020
Dagger matches fields with Kotlin property metadata to generate code that uses property getter methods and/or retrieve qualifier annotations. This CL makes it so that the matching is done lazily and only on fields Dagger is interested on (annotated with @Inject, @BindValue, etc) instead of attempting to match all fields of the TypeElement being processed. This makes it so that the strict requirement of a fields having property metadata is only enforced on relevant fields and other fields, such as those generated by compiler extensions and without metadata get ignored.

Fixes: #2190
RELNOTES=Fix a bug where Dagger was unnecessarily inspecting all fields of a class and attempting to find their Kotlin metadata, failing to do so sometimes and crashing the processor.
PiperOrigin-RevId: 343674753
copybara-service bot pushed a commit that referenced this issue Nov 23, 2020
Dagger matches fields with Kotlin property metadata to generate code that uses property getter methods and/or retrieve qualifier annotations. This CL makes it so that the matching is done lazily and only on fields Dagger is interested on (annotated with @Inject, @BindValue, etc) instead of attempting to match all fields of the TypeElement being processed. This makes it so that the strict requirement of a fields having property metadata is only enforced on relevant fields and other fields, such as those generated by compiler extensions and without metadata get ignored.

Fixes: #2190
RELNOTES=Fix a bug where Dagger was unnecessarily inspecting all fields of a class and attempting to find their Kotlin metadata, failing to do so sometimes and crashing the processor.
PiperOrigin-RevId: 343674753
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants