Skip to content

Commit

Permalink
Merge branch '6.1.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
sdeleuze committed Jun 4, 2024
2 parents 5cd4b87 + f6b608e commit 6212831
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,39 +188,56 @@ private void contributeCallbackHints(RuntimeHints hints, Class<?> managedClass)

@SuppressWarnings("unchecked")
private void contributeHibernateHints(RuntimeHints hints, @Nullable ClassLoader classLoader, Class<?> managedClass) {
Class<? extends Annotation> embeddableInstantiatorClass = loadEmbeddableInstantiatorClass(classLoader);
if (embeddableInstantiatorClass == null) {
return;
}
ReflectionHints reflection = hints.reflection();
registerInstantiatorForReflection(reflection,
AnnotationUtils.findAnnotation(managedClass, embeddableInstantiatorClass));
ReflectionUtils.doWithFields(managedClass, field -> {
registerInstantiatorForReflection(reflection,
AnnotationUtils.findAnnotation(field, embeddableInstantiatorClass));
registerInstantiatorForReflection(reflection,
AnnotationUtils.findAnnotation(field.getType(), embeddableInstantiatorClass));
});
}

@SuppressWarnings("NullAway")
private void registerInstantiatorForReflection(ReflectionHints reflection, @Nullable Annotation annotation) {
if (annotation == null) {
return;
Class<? extends Annotation> embeddableInstantiatorClass = loadClass("org.hibernate.annotations.EmbeddableInstantiator", classLoader);
if (embeddableInstantiatorClass != null) {
registerForReflection(reflection,
AnnotationUtils.findAnnotation(managedClass, embeddableInstantiatorClass), "value");
ReflectionUtils.doWithFields(managedClass, field -> {
registerForReflection(reflection,
AnnotationUtils.findAnnotation(field, embeddableInstantiatorClass), "value");
registerForReflection(reflection,
AnnotationUtils.findAnnotation(field.getType(), embeddableInstantiatorClass), "value");
});
ReflectionUtils.doWithMethods(managedClass, method -> registerForReflection(reflection,
AnnotationUtils.findAnnotation(method, embeddableInstantiatorClass), "value"));
}

Class<? extends Annotation> valueGenerationTypeClass = loadClass("org.hibernate.annotations.ValueGenerationType", classLoader);
if (valueGenerationTypeClass != null) {
ReflectionUtils.doWithFields(managedClass, field -> registerForReflection(reflection,
AnnotationUtils.findAnnotation(field, valueGenerationTypeClass), "generatedBy"));
ReflectionUtils.doWithMethods(managedClass, method -> registerForReflection(reflection,
AnnotationUtils.findAnnotation(method, valueGenerationTypeClass), "generatedBy"));
}

Class<? extends Annotation> idGeneratorTypeClass = loadClass("org.hibernate.annotations.IdGeneratorType", classLoader);
if (idGeneratorTypeClass != null) {
ReflectionUtils.doWithFields(managedClass, field -> registerForReflection(reflection,
AnnotationUtils.findAnnotation(field, idGeneratorTypeClass), "value"));
ReflectionUtils.doWithMethods(managedClass, method -> registerForReflection(reflection,
AnnotationUtils.findAnnotation(method, idGeneratorTypeClass), "value"));
}
Class<?> embeddableInstantiatorClass = (Class<?>) AnnotationUtils.getAnnotationAttributes(annotation).get("value");
reflection.registerType(embeddableInstantiatorClass, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
}

@Nullable
private static Class<? extends Annotation> loadEmbeddableInstantiatorClass(@Nullable ClassLoader classLoader) {
private static Class<? extends Annotation> loadClass(String className, @Nullable ClassLoader classLoader) {
try {
return (Class<? extends Annotation>) ClassUtils.forName(
"org.hibernate.annotations.EmbeddableInstantiator", classLoader);
return (Class<? extends Annotation>) ClassUtils.forName(className, classLoader);
}
catch (ClassNotFoundException ex) {
return null;
}
}

@SuppressWarnings("NullAway")
private void registerForReflection(ReflectionHints reflection, @Nullable Annotation annotation, String attribute) {
if (annotation == null) {
return;
}
Class<?> embeddableInstantiatorClass = (Class<?>) AnnotationUtils.getAnnotationAttributes(annotation).get(attribute);
reflection.registerType(embeddableInstantiatorClass, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2002-2024 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.hibernate.domain;

import java.time.Instant;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.annotations.CreationTimestamp;

@Entity
public class Book {

@Id
private Long id;

private String title;

@CreationTimestamp
private Instant createdOn;

public Book() {
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public Instant getCreatedOn() {
return createdOn;
}

public void setCreatedOn(Instant createdOn) {
this.createdOn = createdOn;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
Expand All @@ -21,6 +21,7 @@

import javax.sql.DataSource;

import org.hibernate.tuple.CreationTimestampGeneration;
import org.junit.jupiter.api.Test;

import org.springframework.aot.hint.MemberCategory;
Expand All @@ -30,7 +31,6 @@
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.aot.ApplicationContextAotGenerator;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ResourceLoader;
Expand Down Expand Up @@ -64,7 +64,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests {
@Test
void processEntityManagerWithPackagesToScan() {
GenericApplicationContext context = new AnnotationConfigApplicationContext();
context.registerBean(EntityManagerWithPackagesToScanConfiguration.class);
context.registerBean(JpaDomainConfiguration.class);
compile(context, (initializer, compiled) -> {
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(
initializer);
Expand All @@ -75,14 +75,14 @@ void processEntityManagerWithPackagesToScan() {
EmployeeLocationConverter.class.getName());
assertThat(persistenceManagedTypes.getManagedPackages()).isEmpty();
assertThat(freshApplicationContext.getBean(
EntityManagerWithPackagesToScanConfiguration.class).scanningInvoked).isFalse();
JpaDomainConfiguration.class).scanningInvoked).isFalse();
});
}

@Test
void contributeHints() {
void contributeJpaHints() {
GenericApplicationContext context = new AnnotationConfigApplicationContext();
context.registerBean(EntityManagerWithPackagesToScanConfiguration.class);
context.registerBean(JpaDomainConfiguration.class);
contributeHints(context, hints -> {
assertThat(RuntimeHintsPredicates.reflection().onType(DriversLicense.class)
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
Expand All @@ -108,6 +108,15 @@ void contributeHints() {
});
}

@Test
void contributeHibernateHints() {
GenericApplicationContext context = new AnnotationConfigApplicationContext();
context.registerBean(HibernateDomainConfiguration.class);
contributeHints(context, hints ->
assertThat(RuntimeHintsPredicates.reflection().onType(CreationTimestampGeneration.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints));
}


@SuppressWarnings("unchecked")
private void compile(GenericApplicationContext applicationContext,
Expand Down Expand Up @@ -135,10 +144,25 @@ private void contributeHints(GenericApplicationContext applicationContext, Consu
result.accept(generationContext.getRuntimeHints());
}

@Configuration(proxyBeanMethods = false)
public static class EntityManagerWithPackagesToScanConfiguration {
public static class JpaDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration {

@Override
protected String packageToScan() {
return "org.springframework.orm.jpa.domain";
}
}

private boolean scanningInvoked;
public static class HibernateDomainConfiguration extends AbstractEntityManagerWithPackagesToScanConfiguration {

@Override
protected String packageToScan() {
return "org.springframework.orm.jpa.hibernate.domain";
}
}

public abstract static class AbstractEntityManagerWithPackagesToScanConfiguration {

protected boolean scanningInvoked;

@Bean
public DataSource mockDataSource() {
Expand All @@ -156,7 +180,7 @@ public HibernateJpaVendorAdapter jpaVendorAdapter() {
public PersistenceManagedTypes persistenceManagedTypes(ResourceLoader resourceLoader) {
this.scanningInvoked = true;
return new PersistenceManagedTypesScanner(resourceLoader)
.scan("org.springframework.orm.jpa.domain");
.scan(packageToScan());
}

@Bean
Expand All @@ -169,6 +193,8 @@ public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource da
return entityManagerFactoryBean;
}

protected abstract String packageToScan();

}

}

0 comments on commit 6212831

Please sign in to comment.