Browse Source

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
pull/29780/head
Sébastien Deleuze 2 years ago
parent
commit
3348e74ab8
  1. 16
      spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java
  2. 24
      spring-orm/src/test/java/org/springframework/orm/jpa/domain/Employee.java
  3. 29
      spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategory.java
  4. 40
      spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategoryConverter.java
  5. 29
      spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKind.java
  6. 40
      spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKindConverter.java
  7. 11
      spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java

16
spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 @@ -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) {

24
spring-orm/src/test/java/org/springframework/orm/jpa/domain/Employee.java

@ -1,5 +1,5 @@ @@ -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 @@ @@ -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; @@ -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 { @@ -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 { @@ -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() {
}

29
spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategory.java

@ -0,0 +1,29 @@ @@ -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;
}
}

40
spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeCategoryConverter.java

@ -0,0 +1,40 @@ @@ -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;
}
}

29
spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKind.java

@ -0,0 +1,29 @@ @@ -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;
}
}

40
spring-orm/src/test/java/org/springframework/orm/jpa/domain/EmployeeKindConverter.java

@ -0,0 +1,40 @@ @@ -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;
}
}

11
spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 { @@ -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…
Cancel
Save