Overview

An unresolved ResolvableType in BeanDefinitionPropertyValueCodeGenerator results in a stack trace similar to the following that occurred while processing an ApplicationContext created from transactionalTests-context.xml in spring-test.

Caused by: java.lang.IllegalArgumentException: 'type' ? must be supported for instance code generation
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:103) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$CollectionDelegate.generateCollectionOf(BeanDefinitionPropertyValueCodeGenerator.java:326) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$CollectionDelegate.generateCollectionCode(BeanDefinitionPropertyValueCodeGenerator.java:315) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$CollectionDelegate.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:309) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:98) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:90) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.addPropertyValues(BeanDefinitionPropertiesCodeGenerator.java:182) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.generateCode(BeanDefinitionPropertiesCodeGenerator.java:128) ~[main/:?]
    at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.generateSetBeanDefinitionPropertiesCode(DefaultBeanRegistrationCodeFragments.java:144) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanRegistrationCodeGenerator.generateCode(BeanRegistrationCodeGenerator.java:86) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.lambda$2(BeanDefinitionMethodGenerator.java:149) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:48) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:85) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:72) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:143) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:107) ~[main/:?]
    at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.generateValueCode(DefaultBeanRegistrationCodeFragments.java:157) ~[main/:?]
    at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.lambda$0(DefaultBeanRegistrationCodeFragments.java:143) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.addPropertyValues(BeanDefinitionPropertiesCodeGenerator.java:180) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.generateCode(BeanDefinitionPropertiesCodeGenerator.java:128) ~[main/:?]
    at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.generateSetBeanDefinitionPropertiesCode(DefaultBeanRegistrationCodeFragments.java:144) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanRegistrationCodeGenerator.generateCode(BeanRegistrationCodeGenerator.java:86) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.lambda$2(BeanDefinitionMethodGenerator.java:149) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:48) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:85) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:72) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:143) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:107) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$2(BeanRegistrationsAotContribution.java:83) ~[main/:?]
    at java.util.LinkedHashMap.forEach(LinkedHashMap.java:721) ~[?:?]
    at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.generateRegisterMethod(BeanRegistrationsAotContribution.java:81) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$1(BeanRegistrationsAotContribution.java:67) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:48) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:85) ~[main/:?]
    at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:72) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.applyTo(BeanRegistrationsAotContribution.java:66) ~[main/:?]
    at org.springframework.context.aot.BeanFactoryInitializationAotContributions.applyTo(BeanFactoryInitializationAotContributions.java:78) ~[main/:?]
    at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$0(ApplicationContextAotGenerator.java:58) ~[main/:?]
    at org.springframework.context.aot.ApplicationContextAotGenerator.withGeneratedClassHandler(ApplicationContextAotGenerator.java:66) ~[main/:?]
    at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53) ~[main/:?]
    at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:149) ~[main/:?]

Related Issues

  • 29013

Comment From: snicoll

@sbrannen How can I reproduce this?

Comment From: sbrannen

Running the following in spring-test will reproduce it.

public static void main(String[] args) {
    GeneratedFiles generatedFiles = new InMemoryGeneratedFiles();
    TestContextAotGenerator generator = new TestContextAotGenerator(generatedFiles);
    generator.processAheadOfTime(Stream.of(MethodLevelTransactionalSpringRunnerTests.class));
}

Comment From: snicoll

Thanks Sam. The problem is that we need to write a ManagedList for CompositeDatabasePopulator and the type of the elements is unknown. I'll see what I can do to support that use case and improve the exception message regardless.

Comment From: snicoll

Let me take this back. This is much simpler. There is a list of inner bean definitions and the code currently doesn't support that. It only support the case where a property or an attribute is a bean definition. Looking at the code, I don't understand why the extra delegate isn't passed to BeanDefinitionPropertyValueCodeGenerator. We used to have a innerBeanDefinitionWriter that was taking care of this to be able to reused in case of a collection.

Comment From: snicoll

I've been spending a few hours on this and I need some help. My attempt is at https://github.com/snicoll/spring-framework/tree/gh-29075.

I've tried to prevent the name of the constructor argument or attribute to be mandatory but that led to some unpleasant code. My thinking is that BeanDefinitionPropertyValueCodeGenerator must be able to handle bean definitions, provided with a custom writer (previous arrangement, for reference). To still transmit the name, I was thinking of wrapping the BeanDefinition in some sort of container, that the custom generator could detect.

This is working but it is extra hard for collections as the generator itself loops over them. If the original value is a collection, you have to create a copy that does the wrapping upfront, with ManagedList & co.

I am also confused about RegisteredBean#isGeneratedBeanName. If we manage to make this work, then BeanDefinitionMethodGenerator no longer needs a @Nullable innerBeanName.