diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java index a2e6586be..28cfd4033 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -66,6 +66,7 @@ public class JpaMetamodelEntityInformation extends J this.metamodel = metamodel; ManagedType type = metamodel.managedType(domainClass); + if (type == null) { throw new IllegalArgumentException("The given domain class can not be found in the given Metamodel!"); } @@ -76,8 +77,10 @@ public class JpaMetamodelEntityInformation extends J throw new IllegalArgumentException("The given domain class does not contain an id attribute!"); } - this.idMetadata = new IdMetadata((IdentifiableType) type); - this.versionAttribute = findVersionAttribute(type); + IdentifiableType identifiableType = (IdentifiableType) type; + + this.idMetadata = new IdMetadata(identifiableType); + this.versionAttribute = findVersionAttribute(identifiableType, metamodel); } /* @@ -93,9 +96,18 @@ public class JpaMetamodelEntityInformation extends J * Returns the version attribute of the given {@link ManagedType} or {@literal null} if none available. * * @param type must not be {@literal null}. + * @param metamodel must not be {@literal null}. * @return */ - private static SingularAttribute findVersionAttribute(ManagedType type) { + @SuppressWarnings("unchecked") + private static SingularAttribute findVersionAttribute(IdentifiableType type, + Metamodel metamodel) { + + try { + return type.getVersion(Object.class); + } catch (IllegalArgumentException o_O) { + // Needs workarounds as the method is implemented with a strict type check on e.g. Hibernate < 4.3 + } Set> attributes = type.getSingularAttributes(); @@ -105,7 +117,21 @@ public class JpaMetamodelEntityInformation extends J } } - return null; + Class superType = type.getJavaType().getSuperclass(); + + try { + + ManagedType managedSuperType = metamodel.managedType(superType); + + if (!(managedSuperType instanceof IdentifiableType)) { + return null; + } + + return (SingularAttribute) findVersionAttribute((IdentifiableType) managedSuperType, metamodel); + + } catch (IllegalArgumentException o_O) { + return null; + } } /* @@ -219,8 +245,8 @@ public class JpaMetamodelEntityInformation extends J public IdMetadata(IdentifiableType source) { this.type = source; - this.attributes = (Set>) (source.hasSingleIdAttribute() ? Collections - .singleton(source.getId(source.getIdType().getJavaType())) : source.getIdClassAttributes()); + this.attributes = (Set>) (source.hasSingleIdAttribute() + ? Collections.singleton(source.getId(source.getIdType().getJavaType())) : source.getIdClassAttributes()); } public boolean hasSimpleId() { @@ -275,8 +301,8 @@ public class JpaMetamodelEntityInformation extends J * * @author Thomas Darimont */ - private static class IdentifierDerivingDirectFieldAccessFallbackBeanWrapper extends - DirectFieldAccessFallbackBeanWrapper { + private static class IdentifierDerivingDirectFieldAccessFallbackBeanWrapper + extends DirectFieldAccessFallbackBeanWrapper { private final Metamodel metamodel; diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java b/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java index 07e407922..2bb4096e9 100644 --- a/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java +++ b/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 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. @@ -18,19 +18,22 @@ package org.springframework.data.jpa.domain.sample; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.MappedSuperclass; +import javax.persistence.Version; /** * @author Thomas Darimont + * @author Oliver Gierke */ @MappedSuperclass public abstract class AbstractMappedType { + @Id @GeneratedValue Long id; + @Version Long version; + String attribute1; + public AbstractMappedType() {} public AbstractMappedType(String attribute1) { this.attribute1 = attribute1; } - - @Id @GeneratedValue Long id; - String attribute1; } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java index 3590c8600..af06b0a3c 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 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. @@ -30,16 +30,16 @@ import org.springframework.test.context.ContextConfiguration; * @author Oliver Gierke */ @ContextConfiguration("classpath:eclipselink.xml") -public class EclipseLinkJpaMetamodelEntityInformationIntegrationTests extends - JpaMetamodelEntityInformationIntegrationTests { +public class EclipseLinkJpaMetamodelEntityInformationIntegrationTests + extends JpaMetamodelEntityInformationIntegrationTests { /** * Re-activate test. Change to check for {@link String} as OpenJpa defaults {@link Serializable}s to {@link String}. */ @Test public void reactivatedDetectsIdTypeForMappedSuperclass() { - JpaEntityInformation information = JpaEntityInformationSupport.getEntityInformation( - AbstractPersistable.class, em); + JpaEntityInformation information = JpaEntityInformationSupport.getEntityInformation(AbstractPersistable.class, + em); assertEquals(String.class, information.getIdType()); } @@ -61,6 +61,14 @@ public class EclipseLinkJpaMetamodelEntityInformationIntegrationTests extends @Ignore public void considersEntityWithUnsetCompundIdNew() {} + /** + * Re-activate test for DATAJPA-820. + */ + @Test + public void detectsVersionPropertyOnMappedSuperClass() { + super.detectsVersionPropertyOnMappedSuperClass(); + } + @Override protected String getMetadadataPersitenceUnitName() { return "metadata_el"; diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java index 0c39a5ef8..a9fd92c48 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-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. @@ -39,6 +39,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.data.jpa.domain.AbstractPersistable; +import org.springframework.data.jpa.domain.sample.ConcreteType1; import org.springframework.data.jpa.domain.sample.PersistableWithIdClass; import org.springframework.data.jpa.domain.sample.PersistableWithIdClassPK; import org.springframework.data.jpa.domain.sample.PrimitiveVersionProperty; @@ -51,6 +52,7 @@ import org.springframework.data.jpa.domain.sample.VersionedUser; import org.springframework.data.repository.core.EntityInformation; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.util.ReflectionTestUtils; /** * Integration tests for {@link JpaMetamodelEntityInformation}. @@ -105,7 +107,8 @@ public class JpaMetamodelEntityInformationIntegrationTests { PersistableWithIdClass entity = new PersistableWithIdClass(2L, 4L); - JpaEntityInformation information = getEntityInformation(PersistableWithIdClass.class, em); + JpaEntityInformation information = getEntityInformation(PersistableWithIdClass.class, + em); Object id = information.getId(entity); assertThat(id, is(instanceOf(PersistableWithIdClassPK.class))); @@ -260,6 +263,19 @@ public class JpaMetamodelEntityInformationIntegrationTests { assertThat(information.isNew(user), is(false)); } + /** + * @see DATAJPA-820 - Ignored as Hibernate < 4.3 doesn't expose the version property properly if it's declared on the + * superclass. + */ + @Test + @Ignore + public void detectsVersionPropertyOnMappedSuperClass() { + + EntityInformation information = getEntityInformation(ConcreteType1.class, em); + + assertThat(ReflectionTestUtils.getField(information, "versionAttribute"), is(notNullValue())); + } + protected String getMetadadataPersitenceUnitName() { return "metadata"; } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java index 5bc55bbcb..04c95cca6 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java @@ -45,17 +45,12 @@ import org.springframework.data.jpa.domain.sample.PersistableWithIdClassPK; @RunWith(MockitoJUnitRunner.class) public class JpaMetamodelEntityInformationUnitTests { - @Mock - Metamodel metamodel; + @Mock Metamodel metamodel; - @Mock - IdentifiableType type; - @Mock - SingularAttribute first, second; + @Mock IdentifiableType type; + @Mock SingularAttribute first, second; - @Mock - @SuppressWarnings("rawtypes") - Type idType; + @Mock @SuppressWarnings("rawtypes") Type idType; @Before @SuppressWarnings("unchecked") @@ -68,6 +63,7 @@ public class JpaMetamodelEntityInformationUnitTests { when(type.getIdClassAttributes()).thenReturn(attributes); + when(metamodel.managedType(Object.class)).thenThrow(IllegalArgumentException.class); when(metamodel.managedType(PersistableWithIdClass.class)).thenReturn(type); when(type.getIdType()).thenReturn(idType); diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java index 0788e3a37..c4ec425fc 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java @@ -39,20 +39,17 @@ import org.springframework.data.repository.core.EntityInformation; @RunWith(MockitoJUnitRunner.class) public class JpaPersistableEntityInformationUnitTests { - @Mock - Metamodel metamodel; + @Mock Metamodel metamodel; - @Mock - EntityType type; + @Mock EntityType type; - @Mock - @SuppressWarnings("rawtypes") - Type idType; + @Mock @SuppressWarnings("rawtypes") Type idType; @Before @SuppressWarnings("unchecked") public void setUp() { + when(metamodel.managedType(Object.class)).thenThrow(IllegalArgumentException.class); when(metamodel.managedType(Foo.class)).thenReturn(type); when(type.getIdType()).thenReturn(idType); } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java index c1a1a6c92..c6d23d347 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 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. @@ -42,6 +42,14 @@ public class OpenJpaMetamodelEntityInformationIntegrationTests extends JpaMetamo @Ignore public void findsIdClassOnMappedSuperclass() {} + /** + * Re-activate test for DATAJPA-820. + */ + @Test + public void detectsVersionPropertyOnMappedSuperClass() { + super.detectsVersionPropertyOnMappedSuperClass(); + } + @Override protected String getMetadadataPersitenceUnitName() { return "metadata_oj";