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 0a03c6a72..531d7dd4c 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 @@ -200,11 +200,7 @@ public class JpaMetamodelEntityInformation extends J BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity); Object versionValue = wrapper.getPropertyValue(versionAttribute.getName()); - if (versionValue == null) { - return true; - } - - return ((Number) versionValue).longValue() == 0; + return versionValue == null; } /** diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClass.java b/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClass.java new file mode 100644 index 000000000..efec47103 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClass.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012 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 + * + * http://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.data.jpa.domain.sample; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; + +import org.springframework.data.domain.Persistable; + +/** + * Sample entity using {@link IdClass} annotation to demarcate ids. + * + * @author Oliver Gierke + */ +@Entity +@IdClass(PersistableWithIdClassPK.class) +public class PersistableWithIdClass implements Persistable { + + private static final long serialVersionUID = 1L; + + @Id + Long first; + + @Id + Long second; + + private boolean isNew; + + protected PersistableWithIdClass() { + this.isNew = true; + } + + public PersistableWithIdClass(Long first, Long second) { + this.first = first; + this.second = second; + this.isNew = true; + } + + /** + * @return the first + */ + public Long getFirst() { + return first; + } + + /** + * @return the second + */ + public Long getSecond() { + return second; + } + + /* (non-Javadoc) + * @see org.springframework.data.domain.Persistable#getId() + */ + public PersistableWithIdClassPK getId() { + return new PersistableWithIdClassPK(first, second); + } + + /* (non-Javadoc) + * @see org.springframework.data.domain.Persistable#isNew() + */ + public boolean isNew() { + return this.isNew; + } + + public void setNotNew() { + this.isNew = false; + } +} diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithIdClassPK.java b/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClassPK.java similarity index 87% rename from src/test/java/org/springframework/data/jpa/domain/sample/SampleWithIdClassPK.java rename to src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClassPK.java index 5d4502844..1e4c0ce88 100644 --- a/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithIdClassPK.java +++ b/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClassPK.java @@ -23,18 +23,18 @@ import java.io.Serializable; * * @author Oliver Gierke */ -public class SampleWithIdClassPK implements Serializable { +public class PersistableWithIdClassPK implements Serializable { private static final long serialVersionUID = 23126782341L; private Long first; private Long second; - public SampleWithIdClassPK() { + public PersistableWithIdClassPK() { } - public SampleWithIdClassPK(Long first, Long second) { + public PersistableWithIdClassPK(Long first, Long second) { this.first = first; this.second = second; } @@ -62,7 +62,7 @@ public class SampleWithIdClassPK implements Serializable { return false; } - SampleWithIdClassPK that = (SampleWithIdClassPK) obj; + PersistableWithIdClassPK that = (PersistableWithIdClassPK) obj; return nullSafeEquals(this.first, that.first) && nullSafeEquals(this.second, that.second); } diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithIdClass.java b/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithIdClass.java index e50c2af9d..a058106ff 100644 --- a/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithIdClass.java +++ b/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithIdClass.java @@ -1,84 +1,54 @@ -/* - * Copyright 2012 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 - * - * http://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.data.jpa.domain.sample; +import java.io.Serializable; + +import javax.persistence.Access; +import javax.persistence.AccessType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; -import org.springframework.data.domain.Persistable; - -/** - * Sample entity using {@link IdClass} annotation to demarcate ids. - * - * @author Oliver Gierke - */ @Entity -@IdClass(SampleWithIdClassPK.class) -public class SampleWithIdClass implements Persistable { +@IdClass(SampleWithIdClass.SampleWithIdClassPK.class) +@Access(AccessType.FIELD) +public class SampleWithIdClass { - private static final long serialVersionUID = 1L; + @Id Long first; + @Id Long second; - @Id - Long first; + @SuppressWarnings("serial") + public static class SampleWithIdClassPK implements Serializable { - @Id - Long second; + Long first; + Long second; - private boolean isNew; + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { - protected SampleWithIdClass() { - this.isNew = true; - } + if (obj == this) { + return true; + } - public SampleWithIdClass(Long first, Long second) { - this.first = first; - this.second = second; - this.isNew = true; - } + if (!(obj instanceof SampleWithIdClassPK)) { + return false; + } - /** - * @return the first - */ - public Long getFirst() { - return first; - } + SampleWithIdClassPK that = (SampleWithIdClassPK) obj; - /** - * @return the second - */ - public Long getSecond() { - return second; - } + return this.first.equals(that.first) && this.second.equals(that.second); + } - /* (non-Javadoc) - * @see org.springframework.data.domain.Persistable#getId() - */ - public SampleWithIdClassPK getId() { - return new SampleWithIdClassPK(first, second); - } - - /* (non-Javadoc) - * @see org.springframework.data.domain.Persistable#isNew() - */ - public boolean isNew() { - return this.isNew; - } - - public void setNotNew() { - this.isNew = false; + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return first.hashCode() + second.hashCode(); + } } } diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithTimestampVersion.java b/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithTimestampVersion.java new file mode 100644 index 000000000..4cef46c56 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithTimestampVersion.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 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 + * + * http://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.data.jpa.domain.sample; + +import java.sql.Timestamp; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class SampleWithTimestampVersion { + + public @Id Long id; + public @Version Timestamp version; +} 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 3c6d27ad5..85efa364a 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 @@ -56,6 +56,14 @@ public class EclipseLinkJpaMetamodelEntityInformationIntegrationTests extends @Ignore public void detectsNewStateForEntityWithPrimitiveId() {} + /* + * (non-Javadoc) + * @see org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformationIntegrationTests#considersEntityWithUnSetCompundIdNew() + */ + @Override + @Ignore + public void considersEntityWithUnsetCompundIdNew() {} + @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 d9e4fad0e..d3340749f 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 @@ -19,6 +19,8 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Date; import javax.persistence.Access; import javax.persistence.AccessType; @@ -36,11 +38,14 @@ 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.PersistableWithIdClass; +import org.springframework.data.jpa.domain.sample.PersistableWithIdClassPK; import org.springframework.data.jpa.domain.sample.PrimitiveVersionProperty; import org.springframework.data.jpa.domain.sample.Role; import org.springframework.data.jpa.domain.sample.SampleWithIdClass; -import org.springframework.data.jpa.domain.sample.SampleWithIdClassPK; +import org.springframework.data.jpa.domain.sample.SampleWithIdClass.SampleWithIdClassPK; import org.springframework.data.jpa.domain.sample.SampleWithPrimitiveId; +import org.springframework.data.jpa.domain.sample.SampleWithTimestampVersion; import org.springframework.data.jpa.domain.sample.User; import org.springframework.data.jpa.domain.sample.VersionedUser; import org.springframework.data.repository.core.EntityInformation; @@ -88,9 +93,9 @@ public class JpaMetamodelEntityInformationIntegrationTests { @Test public void detectsIdClass() { - EntityInformation information = JpaEntityInformationSupport.getMetadata( - SampleWithIdClass.class, em); - assertThat(information.getIdType(), is(typeCompatibleWith(SampleWithIdClassPK.class))); + EntityInformation information = JpaEntityInformationSupport.getMetadata( + PersistableWithIdClass.class, em); + assertThat(information.getIdType(), is(typeCompatibleWith(PersistableWithIdClassPK.class))); } /** @@ -99,14 +104,14 @@ public class JpaMetamodelEntityInformationIntegrationTests { @Test public void returnsIdInstanceCorrectly() { - SampleWithIdClass entity = new SampleWithIdClass(2L, 4L); + PersistableWithIdClass entity = new PersistableWithIdClass(2L, 4L); - JpaEntityInformation information = JpaEntityInformationSupport.getMetadata( - SampleWithIdClass.class, em); + JpaEntityInformation information = JpaEntityInformationSupport.getMetadata( + PersistableWithIdClass.class, em); Object id = information.getId(entity); - assertThat(id, is(instanceOf(SampleWithIdClassPK.class))); - assertThat(id, is((Object) new SampleWithIdClassPK(2L, 4L))); + assertThat(id, is(instanceOf(PersistableWithIdClassPK.class))); + assertThat(id, is((Object) new PersistableWithIdClassPK(2L, 4L))); } /** @@ -216,6 +221,51 @@ public class JpaMetamodelEntityInformationIntegrationTests { assertThat(information.isNew(pvp), is(false)); } + /** + * @see DATAJPA-582 + */ + @Test + public void considersEntityWithUnsetCompundIdNew() { + + EntityInformation information = new JpaMetamodelEntityInformation( + SampleWithIdClass.class, em.getMetamodel()); + + assertThat(information.isNew(new SampleWithIdClass()), is(true)); + } + + /** + * @see DATAJPA-582 + */ + @Test + public void considersEntityWithSetTimestampVersionNotNew() { + + EntityInformation information = getEntityInformation(SampleWithTimestampVersion.class); + + SampleWithTimestampVersion entity = new SampleWithTimestampVersion(); + entity.version = new Timestamp(new Date().getTime()); + + assertThat(information.isNew(entity), is(false)); + } + + /** + * @see DATAJPA-582, DATAJPA-581 + */ + @Test + public void considersEntityWithNonPrimitiveNonNullIdTypeNotNew() { + + EntityInformation information = getEntityInformation(User.class); + + User user = new User(); + assertThat(information.isNew(user), is(true)); + + user.setId(0); + assertThat(information.isNew(user), is(false)); + } + + private EntityInformation getEntityInformation(Class domainType) { + return new JpaMetamodelEntityInformation(domainType, em.getMetamodel()); + } + protected String getMetadadataPersitenceUnitName() { return "metadata"; } @@ -241,5 +291,4 @@ public class JpaMetamodelEntityInformationIntegrationTests { public static class Sample extends Identifiable { } - } 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 56c01c421..5bc55bbcb 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 @@ -34,8 +34,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.data.jpa.domain.sample.SampleWithIdClass; -import org.springframework.data.jpa.domain.sample.SampleWithIdClassPK; +import org.springframework.data.jpa.domain.sample.PersistableWithIdClass; +import org.springframework.data.jpa.domain.sample.PersistableWithIdClassPK; /** * Unit tests for {@link JpaMetamodelEntityInformation}. @@ -49,9 +49,9 @@ public class JpaMetamodelEntityInformationUnitTests { Metamodel metamodel; @Mock - IdentifiableType type; + IdentifiableType type; @Mock - SingularAttribute first, second; + SingularAttribute first, second; @Mock @SuppressWarnings("rawtypes") @@ -63,15 +63,15 @@ public class JpaMetamodelEntityInformationUnitTests { when(first.getName()).thenReturn("first"); when(second.getName()).thenReturn("second"); - Set> attributes = new HashSet>( + Set> attributes = new HashSet>( asList(first, second)); when(type.getIdClassAttributes()).thenReturn(attributes); - when(metamodel.managedType(SampleWithIdClass.class)).thenReturn(type); + when(metamodel.managedType(PersistableWithIdClass.class)).thenReturn(type); when(type.getIdType()).thenReturn(idType); - when(idType.getJavaType()).thenReturn(SampleWithIdClassPK.class); + when(idType.getJavaType()).thenReturn(PersistableWithIdClassPK.class); } /** @@ -80,13 +80,13 @@ public class JpaMetamodelEntityInformationUnitTests { @Test public void doesNotCreateIdIfAllPartialAttributesAreNull() { - JpaMetamodelEntityInformation information = new JpaMetamodelEntityInformation( - SampleWithIdClass.class, metamodel); + JpaMetamodelEntityInformation information = new JpaMetamodelEntityInformation( + PersistableWithIdClass.class, metamodel); - SampleWithIdClass entity = new SampleWithIdClass(null, null); + PersistableWithIdClass entity = new PersistableWithIdClass(null, null); assertThat(information.getId(entity), is(nullValue())); - entity = new SampleWithIdClass(2L, null); + entity = new PersistableWithIdClass(2L, null); assertThat(information.getId(entity), is(notNullValue())); } } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java index b827d9ea9..fc0d843b5 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java @@ -28,8 +28,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.data.jpa.domain.sample.SampleEntity; import org.springframework.data.jpa.domain.sample.SampleEntityPK; -import org.springframework.data.jpa.domain.sample.SampleWithIdClass; -import org.springframework.data.jpa.domain.sample.SampleWithIdClassPK; +import org.springframework.data.jpa.domain.sample.PersistableWithIdClass; +import org.springframework.data.jpa.domain.sample.PersistableWithIdClassPK; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.CrudRepository; import org.springframework.test.context.ContextConfiguration; @@ -50,7 +50,7 @@ public class JpaRepositoryTests { @PersistenceContext EntityManager em; JpaRepository repository; - CrudRepository idClassRepository; + CrudRepository idClassRepository; @Before public void setUp() { @@ -79,13 +79,13 @@ public class JpaRepositoryTests { @Test public void executesCrudOperationsForEntityWithIdClass() { - SampleWithIdClass entity = new SampleWithIdClass(1L, 1L); + PersistableWithIdClass entity = new PersistableWithIdClass(1L, 1L); idClassRepository.save(entity); assertThat(entity.getFirst(), is(notNullValue())); assertThat(entity.getSecond(), is(notNullValue())); - SampleWithIdClassPK id = new SampleWithIdClassPK(entity.getFirst(), entity.getSecond()); + PersistableWithIdClassPK id = new PersistableWithIdClassPK(entity.getFirst(), entity.getSecond()); assertThat(idClassRepository.findOne(id), is(entity)); } @@ -96,12 +96,12 @@ public class JpaRepositoryTests { @Test public void testExistsForDomainObjectsWithCompositeKeys() throws Exception { - SampleWithIdClass s1 = idClassRepository.save(new SampleWithIdClass(1L, 1L)); - SampleWithIdClass s2 = idClassRepository.save(new SampleWithIdClass(2L, 2L)); + PersistableWithIdClass s1 = idClassRepository.save(new PersistableWithIdClass(1L, 1L)); + PersistableWithIdClass s2 = idClassRepository.save(new PersistableWithIdClass(2L, 2L)); assertThat(idClassRepository.exists(s1.getId()), is(true)); assertThat(idClassRepository.exists(s2.getId()), is(true)); - assertThat(idClassRepository.exists(new SampleWithIdClassPK(1L, 2L)), is(false)); + assertThat(idClassRepository.exists(new PersistableWithIdClassPK(1L, 2L)), is(false)); } /** @@ -110,13 +110,13 @@ public class JpaRepositoryTests { @Test public void executesExistsForEntityWithIdClass() { - SampleWithIdClass entity = new SampleWithIdClass(1L, 1L); + PersistableWithIdClass entity = new PersistableWithIdClass(1L, 1L); idClassRepository.save(entity); assertThat(entity.getFirst(), is(notNullValue())); assertThat(entity.getSecond(), is(notNullValue())); - SampleWithIdClassPK id = new SampleWithIdClassPK(entity.getFirst(), entity.getSecond()); + PersistableWithIdClassPK id = new PersistableWithIdClassPK(entity.getFirst(), entity.getSecond()); assertThat(idClassRepository.exists(id), is(true)); } @@ -125,7 +125,7 @@ public class JpaRepositoryTests { } - private static interface SampleWithIdClassRepository extends CrudRepository { + private static interface SampleWithIdClassRepository extends CrudRepository { } } diff --git a/src/test/resources/META-INF/persistence.xml b/src/test/resources/META-INF/persistence.xml index 28c6dd8ff..5a85d4510 100644 --- a/src/test/resources/META-INF/persistence.xml +++ b/src/test/resources/META-INF/persistence.xml @@ -11,6 +11,7 @@ org.springframework.data.jpa.domain.sample.AuditableRole org.springframework.data.jpa.domain.sample.Parent org.springframework.data.jpa.domain.sample.PrimitiveVersionProperty + org.springframework.data.jpa.domain.sample.PersistableWithIdClass org.springframework.data.jpa.domain.sample.Child org.springframework.data.jpa.domain.sample.Role org.springframework.data.jpa.domain.sample.SpecialUser @@ -19,6 +20,7 @@ org.springframework.data.jpa.domain.sample.SampleEntityPK org.springframework.data.jpa.domain.sample.SampleWithIdClass org.springframework.data.jpa.domain.sample.SampleWithPrimitiveId + org.springframework.data.jpa.domain.sample.SampleWithTimestampVersion org.springframework.data.jpa.domain.sample.VersionedUser org.springframework.data.jpa.domain.sample.AbstractMappedType org.springframework.data.jpa.domain.sample.ConcreteType1