From 78a727ace1498afb7fd3dc04ead222aea0fedf8e Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 27 Jan 2015 22:33:54 +0100 Subject: [PATCH] DATAJPA-664 - JpaPersistentProperty.getActualType() now considers special association type. JPA mapping allows to define a specialized target entity type for associations e.g., to be able to use interfaces with associations but actually have them backed by a JPA entity type. JpaPersistentPropertyImpl now favors a type detected within an association property over the one declared at the property for calls to getActualType(). --- .../mapping/JpaPersistentPropertyImpl.java | 46 ++++++++++++++++++- .../JpaPersistentPropertyImplUnitTests.java | 33 ++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) 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 0de1bc24c..0189a2e73 100644 --- a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java +++ b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -37,11 +37,14 @@ import javax.persistence.Transient; import javax.persistence.Version; import javax.persistence.metamodel.Metamodel; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.annotation.AccessType.Type; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; /** @@ -76,6 +79,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty associationTargetType; /** * Creates a new {@link JpaPersistentPropertyImpl} @@ -95,6 +99,26 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty getActualType() { + return associationTargetType == null ? super.getActualType() : associationTargetType.getType(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.model.AbstractPersistentProperty#getPersistentEntityType() + */ + @Override + public Iterable> getPersistentEntityType() { + return associationTargetType == null ? super.getPersistentEntityType() : Collections + .singleton(associationTargetType); } /* @@ -215,4 +239,24 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty detectAssociationTargetType() { + + for (Class associationAnnotation : ASSOCIATION_ANNOTATIONS) { + + Annotation annotation = findAnnotation(associationAnnotation); + Object targetEntity = AnnotationUtils.getValue(annotation, "targetEntity"); + + if (targetEntity != null && !void.class.equals(targetEntity)) { + return ClassTypeInformation.from((Class) targetEntity); + } + } + + return null; + } } diff --git a/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java b/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java index 9b52d61f7..a8d00e1ee 100644 --- a/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.jpa.mapping; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.Collections; @@ -24,6 +24,7 @@ import javax.persistence.Access; import javax.persistence.AccessType; import javax.persistence.Embeddable; import javax.persistence.Embedded; +import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import javax.persistence.Transient; import javax.persistence.metamodel.Metamodel; @@ -35,6 +36,8 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.data.annotation.AccessType.Type; import org.springframework.data.annotation.Version; +import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.TypeInformation; /** * Unit tests for {@link JpaPersistentPropertyImpl}. @@ -161,6 +164,23 @@ public class JpaPersistentPropertyImplUnitTests { assertThat(getProperty(SpringDataVersioned.class, "version").isVersionProperty(), is(true)); } + /** + * @see DATAJPA-664 + */ + @Test + @SuppressWarnings("rawtypes") + public void considersTargetEntityTypeForPropertyType() { + + JpaPersistentProperty property = getProperty(SpecializedAssociation.class, "api"); + + assertThat(property.getType(), is(typeCompatibleWith(Api.class))); + assertThat(property.getActualType(), is(typeCompatibleWith(Implementation.class))); + + Iterable> entityType = property.getPersistentEntityType(); + assertThat(entityType.iterator().hasNext(), is(true)); + assertThat(entityType.iterator().next(), is((TypeInformation) ClassTypeInformation.from(Implementation.class))); + } + private JpaPersistentProperty getProperty(Class ownerType, String propertyName) { JpaPersistentEntity entity = context.getPersistentEntity(ownerType); @@ -270,4 +290,13 @@ public class JpaPersistentPropertyImplUnitTests { @Version long version; } + + static class SpecializedAssociation { + + @ManyToOne(targetEntity = Implementation.class) Api api; + } + + static interface Api {} + + static class Implementation {} }