Browse Source
Update `PersistenceAnnotationBeanPostProcessor` so that it provides AOT contributions via the `BeanRegistrationAotProcessor` interface. See gh-28414pull/28422/head
4 changed files with 690 additions and 1 deletions
@ -0,0 +1,116 @@
@@ -0,0 +1,116 @@
|
||||
/* |
||||
* 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.orm.jpa.support; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Member; |
||||
import java.lang.reflect.Method; |
||||
|
||||
import org.springframework.aot.generate.AccessVisibility; |
||||
import org.springframework.aot.hint.RuntimeHints; |
||||
import org.springframework.javapoet.CodeBlock; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
/** |
||||
* Internal code generator that can inject a value into a field or single-arg |
||||
* method. |
||||
* <p> |
||||
* Generates code in the form:<pre class="code">{@code |
||||
* instance.age = value; |
||||
* }</pre> or <pre class="code">{@code |
||||
* instance.setAge(value); |
||||
* }</pre> |
||||
* <p> |
||||
* Will also generate reflection based injection and register hints if the |
||||
* member is not visible. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 6.0 |
||||
*/ |
||||
class InjectionCodeGenerator { |
||||
|
||||
private final RuntimeHints hints; |
||||
|
||||
|
||||
InjectionCodeGenerator(RuntimeHints hints) { |
||||
Assert.notNull(hints, "Hints must not be null"); |
||||
this.hints = hints; |
||||
} |
||||
|
||||
|
||||
CodeBlock generateInjectionCode(Member member, String instanceVariable, |
||||
CodeBlock resourceToInject) { |
||||
|
||||
if (member instanceof Field field) { |
||||
return generateFieldInjectionCode(field, instanceVariable, resourceToInject); |
||||
} |
||||
if (member instanceof Method method) { |
||||
return generateMethodInjectionCode(method, instanceVariable, |
||||
resourceToInject); |
||||
} |
||||
throw new IllegalStateException( |
||||
"Unsupported member type " + member.getClass().getName()); |
||||
} |
||||
|
||||
private CodeBlock generateFieldInjectionCode(Field field, String instanceVariable, |
||||
CodeBlock resourceToInject) { |
||||
|
||||
CodeBlock.Builder builder = CodeBlock.builder(); |
||||
AccessVisibility visibility = AccessVisibility.forMember(field); |
||||
if (visibility == AccessVisibility.PRIVATE |
||||
|| visibility == AccessVisibility.PROTECTED) { |
||||
this.hints.reflection().registerField(field); |
||||
builder.addStatement("$T field = $T.findField($T.class, $S)", Field.class, |
||||
ReflectionUtils.class, field.getDeclaringClass(), field.getName()); |
||||
builder.addStatement("$T.makeAccessible($L)", ReflectionUtils.class, "field"); |
||||
builder.addStatement("$T.setField($L, $L, $L)", ReflectionUtils.class, |
||||
"field", instanceVariable, resourceToInject); |
||||
} |
||||
else { |
||||
builder.addStatement("$L.$L = $L", instanceVariable, field.getName(), |
||||
resourceToInject); |
||||
} |
||||
return builder.build(); |
||||
} |
||||
|
||||
private CodeBlock generateMethodInjectionCode(Method method, String instanceVariable, |
||||
CodeBlock resourceToInject) { |
||||
|
||||
Assert.isTrue(method.getParameterCount() == 1, |
||||
"Method '" + method.getName() + "' must declare a single parameter"); |
||||
CodeBlock.Builder builder = CodeBlock.builder(); |
||||
AccessVisibility visibility = AccessVisibility.forMember(method); |
||||
if (visibility == AccessVisibility.PRIVATE |
||||
|| visibility == AccessVisibility.PROTECTED) { |
||||
this.hints.reflection().registerMethod(method); |
||||
builder.addStatement("$T method = $T.findMethod($T.class, $S, $T.class)", |
||||
Method.class, ReflectionUtils.class, method.getDeclaringClass(), |
||||
method.getName(), method.getParameterTypes()[0]); |
||||
builder.addStatement("$T.makeAccessible($L)", ReflectionUtils.class, |
||||
"method"); |
||||
builder.addStatement("$T.invokeMethod($L, $L, $L)", ReflectionUtils.class, |
||||
"method", instanceVariable, resourceToInject); |
||||
} |
||||
else { |
||||
builder.addStatement("$L.$L($L)", instanceVariable, method.getName(), |
||||
resourceToInject); |
||||
} |
||||
return builder.build(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,154 @@
@@ -0,0 +1,154 @@
|
||||
/* |
||||
* 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.orm.jpa.support; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Method; |
||||
import java.util.function.BiConsumer; |
||||
import java.util.function.Consumer; |
||||
|
||||
import javax.lang.model.element.Modifier; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.aot.hint.ExecutableMode; |
||||
import org.springframework.aot.hint.RuntimeHints; |
||||
import org.springframework.aot.test.generator.compile.Compiled; |
||||
import org.springframework.aot.test.generator.compile.TestCompiler; |
||||
import org.springframework.beans.testfixture.beans.TestBean; |
||||
import org.springframework.beans.testfixture.beans.TestBeanWithPrivateMethod; |
||||
import org.springframework.beans.testfixture.beans.TestBeanWithPublicField; |
||||
import org.springframework.javapoet.CodeBlock; |
||||
import org.springframework.javapoet.JavaFile; |
||||
import org.springframework.javapoet.MethodSpec; |
||||
import org.springframework.javapoet.ParameterizedTypeName; |
||||
import org.springframework.javapoet.TypeSpec; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link InjectionCodeGenerator}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
class InjectionCodeGeneratorTests { |
||||
|
||||
private static final String INSTANCE_VARIABLE = "instance"; |
||||
|
||||
private RuntimeHints hints = new RuntimeHints(); |
||||
|
||||
private InjectionCodeGenerator generator = new InjectionCodeGenerator(hints); |
||||
|
||||
@Test |
||||
void generateCodeWhenPublicFieldInjectsValue() { |
||||
TestBeanWithPublicField bean = new TestBeanWithPublicField(); |
||||
Field field = ReflectionUtils.findField(bean.getClass(), "age"); |
||||
CodeBlock generatedCode = this.generator.generateInjectionCode(field, INSTANCE_VARIABLE, |
||||
CodeBlock.of("$L", 123)); |
||||
testCompiledResult(generatedCode, TestBeanWithPublicField.class, (actual, compiled) -> { |
||||
TestBeanWithPublicField instance = new TestBeanWithPublicField(); |
||||
actual.accept(instance); |
||||
assertThat(instance).extracting("age").isEqualTo(123); |
||||
assertThat(compiled.getSourceFile()).contains("instance.age = 123"); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void generateCodeWhenPrivateFieldInjectsValueUsingReflection() { |
||||
TestBean bean = new TestBean(); |
||||
Field field = ReflectionUtils.findField(bean.getClass(), "age"); |
||||
CodeBlock generatedCode = this.generator.generateInjectionCode(field, INSTANCE_VARIABLE, |
||||
CodeBlock.of("$L", 123)); |
||||
testCompiledResult(generatedCode, TestBean.class, (actual, compiled) -> { |
||||
TestBean instance = new TestBean(); |
||||
actual.accept(instance); |
||||
assertThat(instance).extracting("age").isEqualTo(123); |
||||
assertThat(compiled.getSourceFile()).contains("setField("); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void generateCodeWhenPrivateFieldAddsHint() { |
||||
TestBean bean = new TestBean(); |
||||
Field field = ReflectionUtils.findField(bean.getClass(), "age"); |
||||
this.generator.generateInjectionCode(field, INSTANCE_VARIABLE, CodeBlock.of("$L", 123)); |
||||
assertThat(this.hints.reflection().getTypeHint(TestBean.class)) |
||||
.satisfies(hint -> assertThat(hint.fields()).anySatisfy(fieldHint -> { |
||||
assertThat(fieldHint.getName()).isEqualTo("age"); |
||||
assertThat(fieldHint.isAllowWrite()).isTrue(); |
||||
})); |
||||
} |
||||
|
||||
@Test |
||||
void generateCodeWhenPublicMethodInjectsValue() { |
||||
TestBean bean = new TestBean(); |
||||
Method method = ReflectionUtils.findMethod(bean.getClass(), "setAge", int.class); |
||||
CodeBlock generatedCode = this.generator.generateInjectionCode(method, INSTANCE_VARIABLE, |
||||
CodeBlock.of("$L", 123)); |
||||
testCompiledResult(generatedCode, TestBean.class, (actual, compiled) -> { |
||||
TestBean instance = new TestBean(); |
||||
actual.accept(instance); |
||||
assertThat(instance).extracting("age").isEqualTo(123); |
||||
assertThat(compiled.getSourceFile()).contains("instance.setAge("); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void generateCodeWhenPrivateMethodInjectsValueUsingReflection() { |
||||
TestBeanWithPrivateMethod bean = new TestBeanWithPrivateMethod(); |
||||
Method method = ReflectionUtils.findMethod(bean.getClass(), "setAge", int.class); |
||||
CodeBlock generatedCode = this.generator.generateInjectionCode(method, INSTANCE_VARIABLE, |
||||
CodeBlock.of("$L", 123)); |
||||
testCompiledResult(generatedCode, TestBeanWithPrivateMethod.class, (actual, compiled) -> { |
||||
TestBeanWithPrivateMethod instance = new TestBeanWithPrivateMethod(); |
||||
actual.accept(instance); |
||||
assertThat(instance).extracting("age").isEqualTo(123); |
||||
assertThat(compiled.getSourceFile()).contains("invokeMethod("); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void generateCodeWhenPrivateMethodAddsHint() { |
||||
TestBeanWithPrivateMethod bean = new TestBeanWithPrivateMethod(); |
||||
Method method = ReflectionUtils.findMethod(bean.getClass(), "setAge", int.class); |
||||
this.generator.generateInjectionCode(method, INSTANCE_VARIABLE, CodeBlock.of("$L", 123)); |
||||
assertThat(this.hints.reflection().getTypeHint(TestBeanWithPrivateMethod.class)) |
||||
.satisfies(hint -> assertThat(hint.methods()).anySatisfy(methodHint -> { |
||||
assertThat(methodHint.getName()).isEqualTo("setAge"); |
||||
assertThat(methodHint.getModes()).contains(ExecutableMode.INVOKE); |
||||
})); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private <T> void testCompiledResult(CodeBlock generatedCode, Class<T> target, |
||||
BiConsumer<Consumer<T>, Compiled> result) { |
||||
JavaFile javaFile = createJavaFile(generatedCode, target); |
||||
TestCompiler.forSystem().compile(javaFile::writeTo, |
||||
compiled -> result.accept(compiled.getInstance(Consumer.class), compiled)); |
||||
} |
||||
|
||||
private JavaFile createJavaFile(CodeBlock generatedCode, Class<?> target) { |
||||
TypeSpec.Builder builder = TypeSpec.classBuilder("Injector"); |
||||
builder.addModifiers(Modifier.PUBLIC); |
||||
builder.addSuperinterface(ParameterizedTypeName.get(Consumer.class, target)); |
||||
builder.addMethod(MethodSpec.methodBuilder("accept").addModifiers(Modifier.PUBLIC) |
||||
.addParameter(target, INSTANCE_VARIABLE).addCode(generatedCode).build()); |
||||
return JavaFile.builder("__", builder.build()).build(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,267 @@
@@ -0,0 +1,267 @@
|
||||
/* |
||||
* 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.orm.jpa.support; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.InvocationHandler; |
||||
import java.lang.reflect.Method; |
||||
import java.lang.reflect.Proxy; |
||||
import java.util.List; |
||||
import java.util.function.BiConsumer; |
||||
|
||||
import jakarta.persistence.EntityManager; |
||||
import jakarta.persistence.EntityManagerFactory; |
||||
import jakarta.persistence.PersistenceContext; |
||||
import jakarta.persistence.PersistenceProperty; |
||||
import jakarta.persistence.PersistenceUnit; |
||||
import org.assertj.core.api.InstanceOfAssertFactories; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.aot.generate.DefaultGenerationContext; |
||||
import org.springframework.aot.generate.InMemoryGeneratedFiles; |
||||
import org.springframework.aot.hint.TypeReference; |
||||
import org.springframework.aot.test.generator.compile.CompileWithTargetClassAccess; |
||||
import org.springframework.aot.test.generator.compile.Compiled; |
||||
import org.springframework.aot.test.generator.compile.TestCompiler; |
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; |
||||
import org.springframework.beans.factory.aot.BeanRegistrationCode; |
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.beans.factory.support.RegisteredBean; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link PersistenceAnnotationBeanPostProcessor} AOT contribution. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Phillip Webb |
||||
*/ |
||||
@CompileWithTargetClassAccess |
||||
class PersistenceAnnotationBeanPostProcessorAotContributionTests { |
||||
|
||||
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
|
||||
private InMemoryGeneratedFiles generatedFiles; |
||||
|
||||
private DefaultGenerationContext generationContext; |
||||
|
||||
@BeforeEach |
||||
void setup() { |
||||
this.beanFactory = new DefaultListableBeanFactory(); |
||||
this.generatedFiles = new InMemoryGeneratedFiles(); |
||||
this.generationContext = new DefaultGenerationContext(generatedFiles); |
||||
} |
||||
|
||||
@Test |
||||
void processAheadOfTimeWhenPersistenceUnitOnPublicField() { |
||||
RegisteredBean registeredBean = registerBean(DefaultPersistenceUnitField.class); |
||||
testCompile(registeredBean, (actual, compiled) -> { |
||||
EntityManagerFactory entityManagerFactory = mock(EntityManagerFactory.class); |
||||
this.beanFactory.registerSingleton("entityManagerFactory", |
||||
entityManagerFactory); |
||||
DefaultPersistenceUnitField instance = new DefaultPersistenceUnitField(); |
||||
actual.accept(registeredBean, instance); |
||||
assertThat(instance).extracting("emf").isSameAs(entityManagerFactory); |
||||
assertThat(this.generationContext.getRuntimeHints().reflection().typeHints()) |
||||
.isEmpty(); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void processAheadOfTimeWhenPersistenceUnitOnPublicSetter() { |
||||
RegisteredBean registeredBean = registerBean(DefaultPersistenceUnitMethod.class); |
||||
testCompile(registeredBean, (actual, compiled) -> { |
||||
EntityManagerFactory entityManagerFactory = mock(EntityManagerFactory.class); |
||||
this.beanFactory.registerSingleton("entityManagerFactory", |
||||
entityManagerFactory); |
||||
DefaultPersistenceUnitMethod instance = new DefaultPersistenceUnitMethod(); |
||||
actual.accept(registeredBean, instance); |
||||
assertThat(instance).extracting("emf").isSameAs(entityManagerFactory); |
||||
assertThat(this.generationContext.getRuntimeHints().reflection().typeHints()) |
||||
.isEmpty(); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void processAheadOfTimeWhenCustomPersistenceUnitOnPublicSetter() { |
||||
RegisteredBean registeredBean = registerBean( |
||||
CustomUnitNamePublicPersistenceUnitMethod.class); |
||||
testCompile(registeredBean, (actual, compiled) -> { |
||||
EntityManagerFactory entityManagerFactory = mock(EntityManagerFactory.class); |
||||
this.beanFactory.registerSingleton("custom", entityManagerFactory); |
||||
CustomUnitNamePublicPersistenceUnitMethod instance = new CustomUnitNamePublicPersistenceUnitMethod(); |
||||
actual.accept(registeredBean, instance); |
||||
assertThat(instance).extracting("emf").isSameAs(entityManagerFactory); |
||||
assertThat(compiled.getSourceFile()).contains( |
||||
"findEntityManagerFactory((ListableBeanFactory) registeredBean.getBeanFactory(), \"custom\")"); |
||||
assertThat(this.generationContext.getRuntimeHints().reflection().typeHints()) |
||||
.isEmpty(); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void processAheadOfTimeWhenPersistenceContextOnPrivateField() { |
||||
RegisteredBean registeredBean = registerBean( |
||||
DefaultPersistenceContextField.class); |
||||
testCompile(registeredBean, (actual, compiled) -> { |
||||
EntityManagerFactory entityManagerFactory = mock(EntityManagerFactory.class); |
||||
this.beanFactory.registerSingleton("entityManagerFactory", |
||||
entityManagerFactory); |
||||
DefaultPersistenceContextField instance = new DefaultPersistenceContextField(); |
||||
actual.accept(registeredBean, instance); |
||||
assertThat(instance).extracting("entityManager").isNotNull(); |
||||
assertThat(this.generationContext.getRuntimeHints().reflection().typeHints()) |
||||
.singleElement().satisfies(typeHint -> { |
||||
assertThat(typeHint.getType()).isEqualTo( |
||||
TypeReference.of(DefaultPersistenceContextField.class)); |
||||
assertThat(typeHint.fields()).singleElement() |
||||
.satisfies(fieldHint -> { |
||||
assertThat(fieldHint.getName()) |
||||
.isEqualTo("entityManager"); |
||||
assertThat(fieldHint.isAllowWrite()).isTrue(); |
||||
assertThat(fieldHint.isAllowUnsafeAccess()).isFalse(); |
||||
}); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void processAheadOfTimeWhenPersistenceContextWithCustomPropertiesOnMethod() { |
||||
RegisteredBean registeredBean = registerBean( |
||||
CustomPropertiesPersistenceContextMethod.class); |
||||
testCompile(registeredBean, (actual, compiled) -> { |
||||
EntityManagerFactory entityManagerFactory = mock(EntityManagerFactory.class); |
||||
this.beanFactory.registerSingleton("entityManagerFactory", |
||||
entityManagerFactory); |
||||
CustomPropertiesPersistenceContextMethod instance = new CustomPropertiesPersistenceContextMethod(); |
||||
actual.accept(registeredBean, instance); |
||||
Field field = ReflectionUtils.findField( |
||||
CustomPropertiesPersistenceContextMethod.class, "entityManager"); |
||||
ReflectionUtils.makeAccessible(field); |
||||
EntityManager sharedEntityManager = (EntityManager) ReflectionUtils |
||||
.getField(field, instance); |
||||
InvocationHandler invocationHandler = Proxy |
||||
.getInvocationHandler(sharedEntityManager); |
||||
assertThat(invocationHandler).extracting("properties") |
||||
.asInstanceOf(InstanceOfAssertFactories.MAP) |
||||
.containsEntry("jpa.test", "value") |
||||
.containsEntry("jpa.test2", "value2"); |
||||
assertThat(this.generationContext.getRuntimeHints().reflection().typeHints()) |
||||
.isEmpty(); |
||||
}); |
||||
} |
||||
|
||||
private RegisteredBean registerBean(Class<?> beanClass) { |
||||
String beanName = "testBean"; |
||||
this.beanFactory.registerBeanDefinition(beanName, |
||||
new RootBeanDefinition(beanClass)); |
||||
return RegisteredBean.of(this.beanFactory, beanName); |
||||
} |
||||
|
||||
private void testCompile(RegisteredBean registeredBean, |
||||
BiConsumer<BiConsumer<RegisteredBean, Object>, Compiled> result) { |
||||
PersistenceAnnotationBeanPostProcessor postProcessor = new PersistenceAnnotationBeanPostProcessor(); |
||||
BeanRegistrationAotContribution contribution = postProcessor |
||||
.processAheadOfTime(registeredBean); |
||||
BeanRegistrationCode beanRegistrationCode = mock(BeanRegistrationCode.class); |
||||
contribution.applyTo(generationContext, beanRegistrationCode); |
||||
TestCompiler.forSystem().withFiles(generatedFiles) |
||||
.compile(compiled -> result.accept(new Invoker(compiled), compiled)); |
||||
} |
||||
|
||||
static class Invoker implements BiConsumer<RegisteredBean, Object> { |
||||
|
||||
private Compiled compiled; |
||||
|
||||
Invoker(Compiled compiled) { |
||||
this.compiled = compiled; |
||||
} |
||||
|
||||
@Override |
||||
public void accept(RegisteredBean registeredBean, Object instance) { |
||||
List<Class<?>> compiledClasses = compiled.getAllCompiledClasses(); |
||||
assertThat(compiledClasses).hasSize(1); |
||||
Class<?> compiledClass = compiledClasses.get(0); |
||||
for (Method method : ReflectionUtils.getDeclaredMethods(compiledClass)) { |
||||
if (method.getName().equals("apply")) { |
||||
ReflectionUtils.invokeMethod(method, null, registeredBean, instance); |
||||
return; |
||||
} |
||||
} |
||||
throw new IllegalStateException("Did not find apply method"); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class DefaultPersistenceUnitField { |
||||
|
||||
@PersistenceUnit |
||||
public EntityManagerFactory emf; |
||||
|
||||
} |
||||
|
||||
static class DefaultPersistenceUnitMethod { |
||||
|
||||
@SuppressWarnings("unused") |
||||
private EntityManagerFactory emf; |
||||
|
||||
@PersistenceUnit |
||||
public void setEmf(EntityManagerFactory emf) { |
||||
this.emf = emf; |
||||
} |
||||
|
||||
} |
||||
|
||||
static class CustomUnitNamePublicPersistenceUnitMethod { |
||||
|
||||
@SuppressWarnings("unused") |
||||
private EntityManagerFactory emf; |
||||
|
||||
@PersistenceUnit(unitName = "custom") |
||||
public void setEmf(EntityManagerFactory emf) { |
||||
this.emf = emf; |
||||
} |
||||
|
||||
} |
||||
|
||||
static class DefaultPersistenceContextField { |
||||
|
||||
@SuppressWarnings("unused") |
||||
@PersistenceContext |
||||
private EntityManager entityManager; |
||||
|
||||
} |
||||
|
||||
static class CustomPropertiesPersistenceContextMethod { |
||||
|
||||
@SuppressWarnings("unused") |
||||
private EntityManager entityManager; |
||||
|
||||
@PersistenceContext( |
||||
properties = { @PersistenceProperty(name = "jpa.test", value = "value"), |
||||
@PersistenceProperty(name = "jpa.test2", value = "value2") }) |
||||
public void setEntityManager(EntityManager entityManager) { |
||||
this.entityManager = entityManager; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue