Add native support for @Convert on JPA entities
This commit infers the reflection hints required for converters when they are specified with the @Convert annotation at class or field level. It also refines the hints generated for @Converter in order to just generate the construct hint, not the public method one which should be not needed. Closes gh-29771
This commit is contained in:
parent
e2832ea596
commit
3348e74ab8
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<EmployeeCategory, String> {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<EmployeeKind, String> {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue