diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java index c7b260daa2..97635aa5e8 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * 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. @@ -23,6 +23,7 @@ import java.util.List; import javax.lang.model.element.Modifier; +import jakarta.persistence.Convert; import jakarta.persistence.Converter; import jakarta.persistence.EntityListeners; import jakarta.persistence.IdClass; @@ -156,9 +157,20 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr private void contributeConverterHints(RuntimeHints hints, Class managedClass) { Converter converter = AnnotationUtils.findAnnotation(managedClass, Converter.class); + ReflectionHints reflectionHints = hints.reflection(); if (converter != null) { - hints.reflection().registerType(managedClass, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS); + reflectionHints.registerType(managedClass, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); } + Convert convertClassAnnotation = AnnotationUtils.findAnnotation(managedClass, Convert.class); + if (convertClassAnnotation != null) { + reflectionHints.registerType(convertClassAnnotation.converter(), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + } + ReflectionUtils.doWithFields(managedClass, field -> { + Convert convertFieldAnnotation = AnnotationUtils.findAnnotation(field, Convert.class); + if (convertFieldAnnotation != null && convertFieldAnnotation.converter() != void.class) { + reflectionHints.registerType(convertFieldAnnotation.converter(), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + } + }); } private void contributeCallbackHints(RuntimeHints hints, Class managedClass) { diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/domain/Employee.java b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/Employee.java index 602fb096c6..fdb6420fc2 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/domain/Employee.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/Employee.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * 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. @@ -17,6 +17,7 @@ package org.springframework.orm.jpa.domain; import jakarta.persistence.Column; +import jakarta.persistence.Convert; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.IdClass; @@ -24,6 +25,7 @@ import jakarta.persistence.PreRemove; @Entity @IdClass(EmployeeId.class) +@Convert(converter = EmployeeKindConverter.class, attributeName = "kind") public class Employee { @Id @@ -36,6 +38,10 @@ public class Employee { private EmployeeLocation location; + @Convert(converter = EmployeeCategoryConverter.class) + private EmployeeCategory category; + + private EmployeeKind kind; public String getName() { return name; @@ -61,6 +67,22 @@ public class Employee { this.location = location; } + public EmployeeCategory getCategory() { + return category; + } + + public void setCategory(EmployeeCategory category) { + this.category = category; + } + + public EmployeeKind getKind() { + return kind; + } + + public void setKind(EmployeeKind kind) { + this.kind = kind; + } + @PreRemove public void preRemove() { } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategory.java b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategory.java new file mode 100644 index 0000000000..785428a31e --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategory.java @@ -0,0 +1,29 @@ +/* + * 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.orm.jpa.domain; + +public class EmployeeCategory { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategoryConverter.java b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategoryConverter.java new file mode 100644 index 0000000000..f51318621a --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategoryConverter.java @@ -0,0 +1,40 @@ +/* + * 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.orm.jpa.domain; + +import jakarta.persistence.AttributeConverter; + +public class EmployeeCategoryConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(EmployeeCategory employeeCategory) { + if (employeeCategory != null) { + return employeeCategory.getName(); + } + return null; + } + + @Override + public EmployeeCategory convertToEntityAttribute(String data) { + if (data != null) { + EmployeeCategory employeeCategory = new EmployeeCategory(); + employeeCategory.setName(data); + return employeeCategory; + } + return null; + } +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKind.java b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKind.java new file mode 100644 index 0000000000..d27e4993b2 --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKind.java @@ -0,0 +1,29 @@ +/* + * 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.orm.jpa.domain; + +public class EmployeeKind { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKindConverter.java b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKindConverter.java new file mode 100644 index 0000000000..a0bbb70a0d --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKindConverter.java @@ -0,0 +1,40 @@ +/* + * 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.orm.jpa.domain; + +import jakarta.persistence.AttributeConverter; + +public class EmployeeKindConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(EmployeeKind employeeKind) { + if (employeeKind != null) { + return employeeKind.getName(); + } + return null; + } + + @Override + public EmployeeKind convertToEntityAttribute(String data) { + if (data != null) { + EmployeeKind employeeKind = new EmployeeKind(); + employeeKind.setName(data); + return employeeKind; + } + return null; + } +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java index c40cb8cdfa..3cfce81b9f 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * 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. @@ -40,7 +40,9 @@ import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.domain.DriversLicense; import org.springframework.orm.jpa.domain.Employee; +import org.springframework.orm.jpa.domain.EmployeeCategoryConverter; import org.springframework.orm.jpa.domain.EmployeeId; +import org.springframework.orm.jpa.domain.EmployeeKindConverter; import org.springframework.orm.jpa.domain.EmployeeLocation; import org.springframework.orm.jpa.domain.EmployeeLocationConverter; import org.springframework.orm.jpa.domain.Person; @@ -96,8 +98,11 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests { assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeId.class) .withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints); assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeLocationConverter.class) - .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS)) - .accepts(hints); + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); + assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeCategoryConverter.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); + assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeKindConverter.class) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeLocation.class) .withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints); });