Browse Source

Restore native support for record beans

After b374824319 related
to gh-29246, `"queryAllDeclaredMethods": true` is now added
on all registered beans.

This legit change triggers oracle/graal#6510. This
commit workarounds this GraalVM bug, and should be
removed once the GraalVM fix has reached a wide enough
audience.

Closes gh-30383
pull/30420/head
Sébastien Deleuze 3 years ago
parent
commit
cefb734763
  1. 12
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java
  2. 27
      spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java
  3. 19
      spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/RecordBean.java

12
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContribution.java

@ -27,6 +27,7 @@ import org.springframework.aot.generate.GenerationContext; @@ -27,6 +27,7 @@ import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.MethodReference;
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.javapoet.ClassName;
@ -109,8 +110,15 @@ class BeanRegistrationsAotContribution @@ -109,8 +110,15 @@ class BeanRegistrationsAotContribution
}
private void generateRegisterHints(RuntimeHints runtimeHints, Map<BeanRegistrationKey, Registration> registrations) {
registrations.keySet().forEach(beanRegistrationKey -> runtimeHints.reflection()
.registerType(beanRegistrationKey.beanClass(), MemberCategory.INTROSPECT_DECLARED_METHODS));
registrations.keySet().forEach(beanRegistrationKey -> {
ReflectionHints hints = runtimeHints.reflection();
Class<?> beanClass = beanRegistrationKey.beanClass();
hints.registerType(beanClass, MemberCategory.INTROSPECT_DECLARED_METHODS);
// Workaround for https://github.com/oracle/graal/issues/6510
if (beanClass.isRecord()) {
hints.registerType(beanClass, MemberCategory.INVOKE_DECLARED_METHODS);
}
});
}
/**

27
spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanRegistrationsAotContributionTests.java

@ -36,6 +36,7 @@ import org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.Re @@ -36,6 +36,7 @@ import org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.Re
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.RecordBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanFactoryInitializationCode;
import org.springframework.core.test.io.support.MockSpringFactoriesLoader;
@ -75,7 +76,7 @@ class BeanRegistrationsAotContributionTests { @@ -75,7 +76,7 @@ class BeanRegistrationsAotContributionTests {
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
registeredBean, null, List.of());
BeanRegistrationsAotContribution contribution = createContribution(generator);
BeanRegistrationsAotContribution contribution = createContribution(TestBean.class, generator);
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
compile((consumer, compiled) -> {
DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory();
@ -89,7 +90,7 @@ class BeanRegistrationsAotContributionTests { @@ -89,7 +90,7 @@ class BeanRegistrationsAotContributionTests {
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
registeredBean, null, List.of());
BeanRegistrationsAotContribution contribution = createContribution(generator, "testAlias");
BeanRegistrationsAotContribution contribution = createContribution(TestBean.class, generator, "testAlias");
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
compile((consumer, compiled) -> {
DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory();
@ -106,7 +107,7 @@ class BeanRegistrationsAotContributionTests { @@ -106,7 +107,7 @@ class BeanRegistrationsAotContributionTests {
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
registeredBean, null, List.of());
BeanRegistrationsAotContribution contribution = createContribution(generator);
BeanRegistrationsAotContribution contribution = createContribution(TestBean.class, generator);
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
compile((consumer, compiled) -> {
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
@ -129,7 +130,7 @@ class BeanRegistrationsAotContributionTests { @@ -129,7 +130,7 @@ class BeanRegistrationsAotContributionTests {
}
};
BeanRegistrationsAotContribution contribution = createContribution(generator);
BeanRegistrationsAotContribution contribution = createContribution(TestBean.class, generator);
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
assertThat(beanRegistrationsCodes).hasSize(1);
BeanRegistrationsCode actual = beanRegistrationsCodes.get(0);
@ -141,13 +142,25 @@ class BeanRegistrationsAotContributionTests { @@ -141,13 +142,25 @@ class BeanRegistrationsAotContributionTests {
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
registeredBean, null, List.of());
BeanRegistrationsAotContribution contribution = createContribution(generator);
BeanRegistrationsAotContribution contribution = createContribution(TestBean.class, generator);
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
assertThat(reflection().onType(TestBean.class)
.withMemberCategory(MemberCategory.INTROSPECT_DECLARED_METHODS))
.accepts(this.generationContext.getRuntimeHints());
}
@Test
void applyToRegisterReflectionHintsOnRecordBean() {
RegisteredBean registeredBean = registerBean(new RootBeanDefinition(RecordBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(this.methodGeneratorFactory,
registeredBean, null, List.of());
BeanRegistrationsAotContribution contribution = createContribution(RecordBean.class, generator);
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
assertThat(reflection().onType(RecordBean.class)
.withMemberCategories(MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_METHODS))
.accepts(this.generationContext.getRuntimeHints());
}
private RegisteredBean registerBean(RootBeanDefinition rootBeanDefinition) {
String beanName = "testBean";
this.beanFactory.registerBeanDefinition(beanName, rootBeanDefinition);
@ -177,10 +190,10 @@ class BeanRegistrationsAotContributionTests { @@ -177,10 +190,10 @@ class BeanRegistrationsAotContributionTests {
result.accept(compiled.getInstance(Consumer.class), compiled));
}
private BeanRegistrationsAotContribution createContribution(
private BeanRegistrationsAotContribution createContribution(Class<?> beanClass,
BeanDefinitionMethodGenerator methodGenerator,String... aliases) {
return new BeanRegistrationsAotContribution(
Map.of(new BeanRegistrationKey("testBean", TestBean.class), new Registration(methodGenerator, aliases)));
Map.of(new BeanRegistrationKey("testBean", beanClass), new Registration(methodGenerator, aliases)));
}
}

19
spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/RecordBean.java

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
/*
* Copyright 2002-2023 the original author or 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
*
* https://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 org.springframework.beans.testfixture.beans;
public record RecordBean(String name) { }
Loading…
Cancel
Save