diff --git a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java index 1d1cad48c..ac18f1437 100644 --- a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java +++ b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java @@ -35,9 +35,7 @@ import javax.persistence.OneToOne; import javax.persistence.OrderColumn; import javax.persistence.Transient; import javax.persistence.Version; -import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.Metamodel; -import javax.persistence.metamodel.SingularAttribute; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.annotation.AccessType.Type; @@ -48,6 +46,7 @@ import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.Lazy; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -97,7 +96,8 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty associationTargetType; private final boolean updateable; private final JpaMetamodel metamodel; - private final EntityType entityType; + + private final Lazy isIdProperty; /** * Creates a new {@link JpaPersistentPropertyImpl} @@ -114,33 +114,13 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty tryResolveEntityType(Metamodel metamodel, Class type) { - - EntityType ownerEntityType = null; - - for (EntityType entityType : metamodel.getEntities()) { - if (entityType.getJavaType().equals(type)) { - ownerEntityType = entityType; - break; - } - } - - return ownerEntityType; + this.isIdProperty = Lazy.of(() -> ID_ANNOTATIONS.stream().anyMatch(it -> isAnnotationPresent(it)) // + || this.metamodel.isSingleIdAttribute(getOwner().getType(), getName(), getType())); } /* @@ -168,27 +148,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty isAnnotationPresent(it)); - - if (isId) { - return true; - } - - if (isIdPropertyCandidateAccordingToMetaModel()) { - - SingularAttribute idAttribute = entityType.getId(getType()); - if (idAttribute.getName().equals(getName())) { - return true; - } - } - - return false; - } - - private boolean isIdPropertyCandidateAccordingToMetaModel() { - return entityType != null && entityType.hasSingleIdAttribute() - && entityType.getIdType().getJavaType().equals(getType()); + return isIdProperty.get(); } /* diff --git a/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java b/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java index ff99cf0f3..ad91cbe2d 100644 --- a/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java +++ b/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java @@ -21,8 +21,10 @@ import java.util.HashSet; import java.util.Optional; import java.util.Set; +import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; +import javax.persistence.metamodel.SingularAttribute; import org.springframework.util.Assert; @@ -63,6 +65,25 @@ public class JpaMetamodel { return getManagedTypes().contains(type); } + /** + * Returns whether the attribute of given name and type is the single identifier attribute of the given entity. + * + * @param entity must not be {@literal null}. + * @param name must not be {@literal null}. + * @param attributeType must not be {@literal null}. + * @return + */ + public boolean isSingleIdAttribute(Class entity, String name, Class attributeType) { + + return metamodel.getEntities().stream() // + .filter(it -> it.getJavaType().equals(entity)) // + .findFirst() // + .flatMap(it -> getSingularIdAttribute(it)) // + .filter(it -> it.getJavaType().equals(attributeType)) // + .map(it -> it.getName().equals(name)) // + .orElse(false); + } + /** * Returns all types managed by the backing {@link Metamodel}. Skips {@link ManagedType} instances that return * {@literal null} for calls to {@link ManagedType#getJavaType()}. @@ -91,4 +112,22 @@ public class JpaMetamodel { return this.managedTypes.get(); } + + /** + * Returns the {@link SingularAttribute} representing the identifier of the given {@link EntityType} if it contains a + * singular one. + * + * @param entityType must not be {@literal null}. + * @return + */ + private static Optional> getSingularIdAttribute(EntityType entityType) { + + if (!entityType.hasSingleIdAttribute()) { + return Optional.empty(); + } + + return entityType.getSingularAttributes().stream() // + .filter(SingularAttribute::isId) // + .findFirst(); + } }