AOT contribution for @PersistenceContext and @PersistenceUnit
Closes gh-28364
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.factory.generator;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.aot.generator.ProtectedAccess.Options;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.support.MultiStatement;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Support for generating {@link Field} access.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.0
|
||||
*/
|
||||
public class BeanFieldGenerator {
|
||||
|
||||
/**
|
||||
* The {@link Options} to use to access a field.
|
||||
*/
|
||||
public static final Options FIELD_OPTIONS = Options.defaults()
|
||||
.useReflection(member -> Modifier.isPrivate(member.getModifiers())).build();
|
||||
|
||||
|
||||
/**
|
||||
* Generate the necessary code to set the specified field. Use reflection
|
||||
* using {@link ReflectionUtils} if necessary.
|
||||
* @param field the field to set
|
||||
* @param value a code representation of the field value
|
||||
* @return the code to set the specified field
|
||||
*/
|
||||
public MultiStatement generateSetValue(String target, Field field, CodeBlock value) {
|
||||
MultiStatement statement = new MultiStatement();
|
||||
boolean useReflection = Modifier.isPrivate(field.getModifiers());
|
||||
if (useReflection) {
|
||||
String fieldName = String.format("%sField", field.getName());
|
||||
statement.addStatement("$T $L = $T.findField($T.class, $S)", Field.class, fieldName, ReflectionUtils.class,
|
||||
field.getDeclaringClass(), field.getName());
|
||||
statement.addStatement("$T.makeAccessible($L)", ReflectionUtils.class, fieldName);
|
||||
statement.addStatement("$T.setField($L, $L, $L)", ReflectionUtils.class, fieldName, target, value);
|
||||
}
|
||||
else {
|
||||
statement.addStatement("$L.$L = $L", target, field.getName(), value);
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import org.springframework.beans.factory.generator.config.BeanDefinitionRegistra
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.CodeBlock.Builder;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Generate the necessary code to {@link #generateInstantiation(Executable)
|
||||
@@ -53,14 +52,13 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public class InjectionGenerator {
|
||||
|
||||
private static final Options FIELD_INJECTION_OPTIONS = Options.defaults()
|
||||
.useReflection(member -> Modifier.isPrivate(member.getModifiers())).build();
|
||||
|
||||
private static final Options METHOD_INJECTION_OPTIONS = Options.defaults()
|
||||
.useReflection(member -> false).build();
|
||||
|
||||
private final BeanParameterGenerator parameterGenerator = new BeanParameterGenerator();
|
||||
|
||||
private final BeanFieldGenerator fieldGenerator = new BeanFieldGenerator();
|
||||
|
||||
|
||||
/**
|
||||
* Generate the necessary code to instantiate an object using the specified
|
||||
@@ -110,7 +108,7 @@ public class InjectionGenerator {
|
||||
return METHOD_INJECTION_OPTIONS;
|
||||
}
|
||||
if (member instanceof Field) {
|
||||
return FIELD_INJECTION_OPTIONS;
|
||||
return BeanFieldGenerator.FIELD_OPTIONS;
|
||||
}
|
||||
throw new IllegalArgumentException("Could not handle member " + member);
|
||||
}
|
||||
@@ -230,24 +228,13 @@ public class InjectionGenerator {
|
||||
code.add("instanceContext.field($S", injectionPoint.getName());
|
||||
code.add(")\n").indent().indent();
|
||||
if (required) {
|
||||
code.add(".invoke(beanFactory, (attributes) ->");
|
||||
code.add(".invoke(beanFactory, ");
|
||||
}
|
||||
else {
|
||||
code.add(".resolve(beanFactory, false).ifResolved((attributes) ->");
|
||||
}
|
||||
boolean hasAssignment = Modifier.isPrivate(injectionPoint.getModifiers());
|
||||
if (hasAssignment) {
|
||||
code.beginControlFlow("");
|
||||
String fieldName = String.format("%sField", injectionPoint.getName());
|
||||
code.addStatement("$T $L = $T.findField($T.class, $S)", Field.class, fieldName, ReflectionUtils.class,
|
||||
injectionPoint.getDeclaringClass(), injectionPoint.getName());
|
||||
code.addStatement("$T.makeAccessible($L)", ReflectionUtils.class, fieldName);
|
||||
code.addStatement("$T.setField($L, bean, attributes.get(0))", ReflectionUtils.class, fieldName);
|
||||
code.unindent().add("}");
|
||||
}
|
||||
else {
|
||||
code.add(" bean.$L = attributes.get(0)", injectionPoint.getName());
|
||||
code.add(".resolve(beanFactory, false).ifResolved(");
|
||||
}
|
||||
code.add(this.fieldGenerator.generateSetValue("bean", injectionPoint,
|
||||
CodeBlock.of("attributes.get(0)")).toLambdaBody("(attributes) ->"));
|
||||
code.add(")").unindent().unindent();
|
||||
return code.build();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.factory.generator;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.support.CodeSnippet;
|
||||
import org.springframework.javapoet.support.MultiStatement;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link BeanFieldGenerator}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class BeanFieldGeneratorTests {
|
||||
|
||||
private final BeanFieldGenerator generator = new BeanFieldGenerator();
|
||||
|
||||
@Test
|
||||
void generateSetFieldWithPublicField() {
|
||||
MultiStatement statement = this.generator.generateSetValue("bean",
|
||||
field(SampleBean.class, "one"), CodeBlock.of("$S", "test"));
|
||||
assertThat(CodeSnippet.process(statement.toCodeBlock())).isEqualTo("""
|
||||
bean.one = "test";
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateSetFieldWithPrivateField() {
|
||||
MultiStatement statement = this.generator.generateSetValue("example",
|
||||
field(SampleBean.class, "two"), CodeBlock.of("42"));
|
||||
CodeSnippet code = CodeSnippet.of(statement.toCodeBlock());
|
||||
assertThat(code.getSnippet()).isEqualTo("""
|
||||
Field twoField = ReflectionUtils.findField(BeanFieldGeneratorTests.SampleBean.class, "two");
|
||||
ReflectionUtils.makeAccessible(twoField);
|
||||
ReflectionUtils.setField(twoField, example, 42);
|
||||
""");
|
||||
assertThat(code.hasImport(ReflectionUtils.class)).isTrue();
|
||||
assertThat(code.hasImport(BeanFieldGeneratorTests.class)).isTrue();
|
||||
}
|
||||
|
||||
|
||||
private Field field(Class<?> type, String name) {
|
||||
Field field = ReflectionUtils.findField(type, name);
|
||||
assertThat(field).isNotNull();
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
public static class SampleBean {
|
||||
|
||||
public String one;
|
||||
|
||||
private int two;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user