Overview

When BeanDefinitionPropertyValueCodeGenerator.MapDelegate generates code for a Map, that map may contain instances of TypedStringValue resulting in a stack trace similar to the following that occurred while processing an ApplicationContext created from ExpressionUsageTests-context.xml in spring-test. We should likely replace typed string values with actual values before generating the map.

Caused by: java.lang.ClassCastException: class org.springframework.beans.factory.config.TypedStringValue cannot be cast to class java.lang.Comparable (org.springframework.beans.factory.config.TypedStringValue is in unnamed module of loader org.springframework.aot.test.generator.compile.CompileWithTargetClassAccessClassLoader @24a1c17f; java.lang.Comparable is in module java.base of loader 'bootstrap')
    at java.util.TreeMap.compare(TreeMap.java:1569) ~[?:?]
    at java.util.TreeMap.addEntryToEmptyMap(TreeMap.java:776) ~[?:?]
    at java.util.TreeMap.put(TreeMap.java:785) ~[?:?]
    at java.util.TreeMap.put(TreeMap.java:534) ~[?:?]
    at java.util.AbstractMap.putAll(AbstractMap.java:281) ~[?:?]
    at java.util.TreeMap.putAll(TreeMap.java:326) ~[?:?]
    at java.util.TreeMap.<init>(TreeMap.java:187) ~[?:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$MapDelegate.orderForCodeConsistency(BeanDefinitionPropertyValueCodeGenerator.java:497) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$MapDelegate.generateMapCode(BeanDefinitionPropertyValueCodeGenerator.java:471) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator$MapDelegate.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:457) ~[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:115) ~[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/:?]

BeanDefinitionPropertyValueCodeGenerator may need a TypedStringValueDelegate (or similar), because without one we see stack traces similar to the following that occurred while processing an ApplicationContext created from SpringJUnit4ClassRunnerAppCtxTests-context.xml in spring-test.

Caused by: java.lang.IllegalArgumentException: 'type' org.springframework.beans.factory.config.TypedStringValue must be supported for instance code generation
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:102) ~[main/:?]
    at org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGenerator.generateCode(BeanDefinitionPropertyValueCodeGenerator.java:89) ~[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.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

There's also the problem that ConstructorOrFactoryMethodResolver isn't resolving TypedStringValue at the moment. When computing the arguments to use to identify a matching constructor, it takes the raw TypedStringValue.

This is one more case that links to https://github.com/spring-projects/spring-framework/issues/27920

Comment From: snicoll

I am not yet convinced that we have to handle TypedStringValue like that. Rather I was hoping that the resolved constructor would give us the arguments needed, and the generator would write an indexed argument.

Comment From: snicoll

Blocked by https://github.com/spring-projects/spring-framework/issues/27920

Comment From: ganapathi004

Any known workaround until the support is added? We are trying to convert one of our projects with XML configuration to Spring Boot 3 Native Image.

Comment From: snicoll

We've made quite a bit of progress in better support for XML configs but there is still one major point to review, see https://github.com/spring-projects/spring-framework/issues/31420. Please keep testing against the latest version, thanks!