Courtesy of @wilkinsona https://github.com/snicoll-scratches/lost-target-type
To reproduce:
./gradlew bootJar
java -Dspring.aot.enabled=true -jar build/libs/lost-target-type-0.0.1-SNAPSHOT.jar
The use case is registering a bean definition on the fly with the factory method of another bean definition, but perhaps this can be generalized.
The bean definition looks like this:
public static BeanDefinition getTwoBeanDefinition() {
Class<?> beanType = LostTargetTypeApplication.Two.class;
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
beanDefinition.setInstanceSupplier(getTwoInstanceSupplier());
return beanDefinition;
}
Its instance supplier refers to a method that's going to produce a bean of type One
. One
and Two
are unrelated and the factory method produces an instance that implements them both.
It looks like the bean definition's bean class is ignored in favor of the bean factory method. The following works:
public static BeanDefinition getTwoBeanDefinition() {
Class<?> beanType = LostTargetTypeApplication.Two.class;
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
beanDefinition.setInstanceSupplier(getTwoInstanceSupplier());
beanDefinition.setTargetType(beanType);
return beanDefinition;
}
We should review this use case and see whether AOT has to generate a more precise definition or if the context should fallback first on the bean class.
Comment From: snicoll
It turns out that we should do our best to generate the necessary code to restore the target type if it has been explicitly set on the BeanDefinition
.
Comment From: snicoll
So it turns out that the previous arrangement was a bit odd where generated code would set the beanClass
attribute for a non-generic resolved type, and the targetType
otherwise (i.e. for resolved type with generics).
We're now more consistent, only applying the beanClass
if it is set in the original bean definition and setting the targetType
consistently as it is suitable for scenarios where the type has been determined upfront. This review of type handling also led to deprecate a constructor that was added for the previous arrangement, see #30704.