From 6635836324f3c4dc30de5d9c95dce5caa576d547 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 18 Jul 2016 11:51:46 +0200 Subject: [PATCH] DATAJPA-413 - Guard identifier derivation against null values and add tests. Added guard against null values in identifiers. Null values can occur because id generation was not completed yet. Add tests for identifier derivation using @IdClass for Hibernate, OpenJPA and EclipseLink. Original pull request: #133. --- .../JpaMetamodelEntityInformation.java | 20 +++-- .../data/jpa/domain/sample/Item.java | 61 +++++++++++++ .../data/jpa/domain/sample/ItemId.java | 75 ++++++++++++++++ .../data/jpa/domain/sample/ItemSite.java | 60 +++++++++++++ .../data/jpa/domain/sample/ItemSiteId.java | 59 +++++++++++++ .../data/jpa/domain/sample/Site.java | 47 ++++++++++ ...itoryWithCompositeKeyIntegrationTests.java | 31 +++++++ ...itoryWithCompositeKeyIntegrationTests.java | 33 +++++++ .../RepositoryWithIdClassKeyTests.java | 88 +++++++++++++++++++ .../jpa/repository/sample/ItemRepository.java | 27 ++++++ .../repository/sample/ItemSiteRepository.java | 27 ++++++ .../jpa/repository/sample/SiteRepository.java | 26 ++++++ ...odelEntityInformationIntegrationTests.java | 58 +++++++++++- src/test/resources/META-INF/persistence.xml | 3 + src/test/resources/META-INF/persistence2.xml | 8 +- 15 files changed, 614 insertions(+), 9 deletions(-) create mode 100755 src/test/java/org/springframework/data/jpa/domain/sample/Item.java create mode 100755 src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java create mode 100755 src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java create mode 100755 src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java create mode 100644 src/test/java/org/springframework/data/jpa/domain/sample/Site.java create mode 100644 src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java create mode 100644 src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java create mode 100644 src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java create mode 100755 src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java create mode 100755 src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java create mode 100755 src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java 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 7245371ed..c92c61d48 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-2015 the original author or authors. + * Copyright 2011-2016 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. @@ -45,6 +45,7 @@ import org.springframework.util.ClassUtils; * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public class JpaMetamodelEntityInformation extends JpaEntityInformationSupport { @@ -297,7 +298,7 @@ public class JpaMetamodelEntityInformation extends J } /** - * Custom extension of {@link DirectFieldAccessFallbackBeanWrapper} that allows to derived the identifier if composite + * Custom extension of {@link DirectFieldAccessFallbackBeanWrapper} that allows to derive the identifier if composite * keys with complex key attribute types (e.g. types that are annotated with {@code @Entity} themselves) are used. * * @author Thomas Darimont @@ -358,14 +359,19 @@ public class JpaMetamodelEntityInformation extends J Object idPropertyValue = sourceIdValueWrapper.getPropertyValue(idAttributeName); - Class idPropertyValueType = idPropertyValue.getClass(); + if (idPropertyValue != null) { - if (ClassUtils.isPrimitiveOrWrapper(idPropertyValueType)) { - return idPropertyValue; + Class idPropertyValueType = idPropertyValue.getClass(); + + if (ClassUtils.isPrimitiveOrWrapper(idPropertyValueType)) { + return idPropertyValue; + } + + return new DirectFieldAccessFallbackBeanWrapper(idPropertyValue) + .getPropertyValue(tryFindSingularIdAttributeNameOrUseFallback(idPropertyValueType, idAttributeName)); } - return new DirectFieldAccessFallbackBeanWrapper(idPropertyValue) - .getPropertyValue(tryFindSingularIdAttributeNameOrUseFallback(idPropertyValueType, idAttributeName)); + return null; } private String tryFindSingularIdAttributeNameOrUseFallback(Class idPropertyValueType, diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/Item.java b/src/test/java/org/springframework/data/jpa/domain/sample/Item.java new file mode 100755 index 000000000..2d85c6140 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/Item.java @@ -0,0 +1,61 @@ +/* + * Copyright 2016 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.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.Table; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +@Entity +@Table +@IdClass(ItemId.class) +public class Item { + + @Id @Column(columnDefinition = "INT") Integer id; + + @Id @JoinColumn(name = "manufacturer_id", columnDefinition = "INT") Integer manufacturerId; + + public Item() {} + + public Item(Integer id, Integer manufacturerId) { + this.id = id; + this.manufacturerId = manufacturerId; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getManufacturerId() { + return manufacturerId; + } + + public void setManufacturerId(Integer manufacturerId) { + this.manufacturerId = manufacturerId; + } +} diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java b/src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java new file mode 100755 index 000000000..2622519e8 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java @@ -0,0 +1,75 @@ +/* + * Copyright 2016 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; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +public class ItemId implements Serializable { + + private static final long serialVersionUID = -2986871112875450036L; + + Integer id; + Integer manufacturerId; + + public ItemId() {} + + public ItemId(Integer id, Integer manufacturerId) { + this.id = id; + this.manufacturerId = manufacturerId; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getManufacturerId() { + return manufacturerId; + } + + public void setManufacturerId(Integer manufacturerId) { + this.manufacturerId = manufacturerId; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof ItemId)) + return false; + + ItemId itemId = (ItemId) o; + + if (id != null ? !id.equals(itemId.id) : itemId.id != null) + return false; + return manufacturerId != null ? manufacturerId.equals(itemId.manufacturerId) : itemId.manufacturerId == null; + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (manufacturerId != null ? manufacturerId.hashCode() : 0); + return result; + } +} diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java b/src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java new file mode 100755 index 000000000..f3aa8c9dc --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java @@ -0,0 +1,60 @@ +/* + * Copyright 2016 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 javax.persistence.ManyToOne; +import javax.persistence.Table; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +@Entity +@Table +@IdClass(ItemSiteId.class) +public class ItemSite { + + @Id @ManyToOne Item item; + + @Id @ManyToOne Site site; + + public ItemSite() {} + + public ItemSite(Item item, Site site) { + this.item = item; + this.site = site; + } + + public Item getItem() { + return item; + } + + public void setItem(Item item) { + this.item = item; + } + + public Site getSite() { + return site; + } + + public void setSite(Site site) { + this.site = site; + } +} diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java b/src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java new file mode 100755 index 000000000..c62e6ae98 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 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; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +public class ItemSiteId implements Serializable { + + private static final long serialVersionUID = 1822540289216799357L; + + ItemId item; + Integer site; + + public ItemSiteId() {} + + public ItemSiteId(ItemId item, Integer site) { + this.item = item; + this.site = site; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof ItemSiteId)) + return false; + + ItemSiteId that = (ItemSiteId) o; + + if (item != null ? !item.equals(that.item) : that.item != null) + return false; + return site != null ? site.equals(that.site) : that.site == null; + } + + @Override + public int hashCode() { + int result = item != null ? item.hashCode() : 0; + result = 31 * result + (site != null ? site.hashCode() : 0); + return result; + } +} diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/Site.java b/src/test/java/org/springframework/data/jpa/domain/sample/Site.java new file mode 100644 index 000000000..7acbcd245 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/Site.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 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.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +@Entity +@Table +public class Site implements java.io.Serializable { + + @Id @GeneratedValue Integer id; + + public Site() {} + + public Site(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java new file mode 100644 index 000000000..40499345f --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java @@ -0,0 +1,31 @@ +/* + * Copyright 2016 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.repository; + +import org.springframework.context.annotation.ImportResource; +import org.springframework.test.context.ContextConfiguration; + +/** + * Testcase to run {@link RepositoryWithIdClassKeyTests} integration tests on top of EclipseLink. + * + * @author Mark Paluch + */ +@ContextConfiguration +public class EclipseLinkRepositoryWithCompositeKeyIntegrationTests extends RepositoryWithIdClassKeyTests { + + @ImportResource({ "classpath:infrastructure.xml", "classpath:eclipselink.xml" }) + static class TestConfig extends Config {} +} diff --git a/src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java new file mode 100644 index 000000000..8e77b670f --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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.repository; + +import org.springframework.context.annotation.ImportResource; +import org.springframework.test.context.ContextConfiguration; + +/** + * Testcase to run {@link RepositoryWithIdClassKeyTests} integration tests on top of OpenJPA. + * + * @author Mark Paluch + */ +@ContextConfiguration +public class OpenJpaRepositoryWithCompositeKeyIntegrationTests extends RepositoryWithIdClassKeyTests { + + @ImportResource({ "classpath:infrastructure.xml", "classpath:openjpa.xml" }) + static class TestConfig extends Config { + + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java b/src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java new file mode 100644 index 000000000..8ac72b9e5 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2016 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.repository; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.data.jpa.domain.sample.Item; +import org.springframework.data.jpa.domain.sample.ItemId; +import org.springframework.data.jpa.domain.sample.ItemSite; +import org.springframework.data.jpa.domain.sample.ItemSiteId; +import org.springframework.data.jpa.domain.sample.Site; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.data.jpa.repository.sample.ItemRepository; +import org.springframework.data.jpa.repository.sample.ItemSiteRepository; +import org.springframework.data.jpa.repository.sample.SampleConfig; +import org.springframework.data.jpa.repository.sample.SiteRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +/** + * Integration tests for Repositories using {@link javax.persistence.IdClass} identifiers. + * + * @author Mark Paluch + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = RepositoryWithIdClassKeyTests.TestConfig.class) +@Transactional +public class RepositoryWithIdClassKeyTests { + + @Rule public ExpectedException expectedException = ExpectedException.none(); + + @Autowired private SiteRepository siteRepository; + + @Autowired private ItemRepository itemRepository; + + @Autowired private ItemSiteRepository itemSiteRepository; + + @Configuration + @EnableJpaRepositories(basePackageClasses = SampleConfig.class) + static abstract class Config { + + } + + @ImportResource("classpath:infrastructure.xml") + static class TestConfig extends Config { + + } + + /** + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ + @Test + public void shouldSaveAndLoadEntitiesWithDerivedIdentities() throws Exception { + + Site site = siteRepository.save(new Site()); + Item item = itemRepository.save(new Item(123, 456)); + + itemSiteRepository.save(new ItemSite(item, site)); + + ItemSite loaded = itemSiteRepository + .findOne(new ItemSiteId(new ItemId(item.getId(), item.getManufacturerId()), site.getId())); + + assertThat(loaded, is(notNullValue())); + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java new file mode 100755 index 000000000..7211ef610 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2016 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.repository.sample; + +import org.springframework.data.jpa.domain.sample.Item; +import org.springframework.data.jpa.domain.sample.ItemId; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +public interface ItemRepository extends JpaRepository {} diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java new file mode 100755 index 000000000..5579f8942 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2016 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.repository.sample; + +import org.springframework.data.jpa.domain.sample.ItemSite; +import org.springframework.data.jpa.domain.sample.ItemSiteId; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +public interface ItemSiteRepository extends JpaRepository {} diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java new file mode 100755 index 000000000..03f14d39d --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2016 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.repository.sample; + +import org.springframework.data.jpa.domain.sample.Site; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author Mark Paluch + * @see DATAJPA-413 + * @see Final JPA 2.1 Specification 2.4.1.3 Derived Identities Example 2 + */ +public interface SiteRepository extends JpaRepository {} 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 a9fd92c48..c83fdbaff 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 @@ -40,6 +40,10 @@ 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.Item; +import org.springframework.data.jpa.domain.sample.ItemId; +import org.springframework.data.jpa.domain.sample.ItemSite; +import org.springframework.data.jpa.domain.sample.ItemSiteId; import org.springframework.data.jpa.domain.sample.PersistableWithIdClass; import org.springframework.data.jpa.domain.sample.PersistableWithIdClassPK; import org.springframework.data.jpa.domain.sample.PrimitiveVersionProperty; @@ -47,6 +51,7 @@ import org.springframework.data.jpa.domain.sample.Role; import org.springframework.data.jpa.domain.sample.SampleWithIdClass; import org.springframework.data.jpa.domain.sample.SampleWithPrimitiveId; import org.springframework.data.jpa.domain.sample.SampleWithTimestampVersion; +import org.springframework.data.jpa.domain.sample.Site; import org.springframework.data.jpa.domain.sample.User; import org.springframework.data.jpa.domain.sample.VersionedUser; import org.springframework.data.repository.core.EntityInformation; @@ -103,7 +108,7 @@ public class JpaMetamodelEntityInformationIntegrationTests { * @see DATAJPA-50 */ @Test - public void returnsIdInstanceCorrectly() { + public void returnsIdOfPersistableInstanceCorrectly() { PersistableWithIdClass entity = new PersistableWithIdClass(2L, 4L); @@ -115,6 +120,57 @@ public class JpaMetamodelEntityInformationIntegrationTests { assertThat(id, is((Object) new PersistableWithIdClassPK(2L, 4L))); } + /** + * @see DATAJPA-413 + */ + @Test + public void returnsIdOfEntityWithIdClassCorrectly() { + + Item item = new Item(2, 1); + + JpaEntityInformation information = getEntityInformation(Item.class, em); + Object id = information.getId(item); + + assertThat(id, is(instanceOf(ItemId.class))); + assertThat(id, is((Object) new ItemId(2, 1))); + } + + /** + * @see DATAJPA-413 + */ + @Test + public void returnsDerivedIdOfEntityWithIdClassCorrectly() { + + Item item = new Item(1, 2); + Site site = new Site(3); + + ItemSite itemSite = new ItemSite(item, site); + + JpaEntityInformation information = getEntityInformation(ItemSite.class, em); + Object id = information.getId(itemSite); + + assertThat(id, is(instanceOf(ItemSiteId.class))); + assertThat(id, is((Object) new ItemSiteId(new ItemId(1, 2), 3))); + } + + /** + * @see DATAJPA-413 + */ + @Test + public void returnsPartialEmptyDerivedIdOfEntityWithIdClassCorrectly() { + + Item item = new Item(1, null); + Site site = new Site(3); + + ItemSite itemSite = new ItemSite(item, site); + + JpaEntityInformation information = getEntityInformation(ItemSite.class, em); + Object id = information.getId(itemSite); + + assertThat(id, is(instanceOf(ItemSiteId.class))); + assertThat(id, is((Object) new ItemSiteId(new ItemId(1, null), 3))); + } + /** * @see DATAJPA-119 */ diff --git a/src/test/resources/META-INF/persistence.xml b/src/test/resources/META-INF/persistence.xml index 82189b1b0..ea0e22431 100644 --- a/src/test/resources/META-INF/persistence.xml +++ b/src/test/resources/META-INF/persistence.xml @@ -21,6 +21,8 @@ org.springframework.data.jpa.domain.sample.EmbeddedIdExampleDepartment org.springframework.data.jpa.domain.sample.IdClassExampleEmployee org.springframework.data.jpa.domain.sample.IdClassExampleDepartment + org.springframework.data.jpa.domain.sample.Item + org.springframework.data.jpa.domain.sample.ItemSite org.springframework.data.jpa.domain.sample.MailMessage org.springframework.data.jpa.domain.sample.MailSender org.springframework.data.jpa.domain.sample.MailUser @@ -35,6 +37,7 @@ 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.Site org.springframework.data.jpa.domain.sample.SpecialUser org.springframework.data.jpa.domain.sample.User org.springframework.data.jpa.domain.sample.VersionedUser diff --git a/src/test/resources/META-INF/persistence2.xml b/src/test/resources/META-INF/persistence2.xml index 18c3c67b1..a2164a9f0 100644 --- a/src/test/resources/META-INF/persistence2.xml +++ b/src/test/resources/META-INF/persistence2.xml @@ -7,12 +7,15 @@ org.springframework.data.jpa.domain.sample.AuditableRole org.springframework.data.jpa.domain.sample.AuditableUser org.springframework.data.jpa.domain.sample.Category -org.springframework.data.jpa.domain.sample.CustomAbstractPersistable + org.springframework.data.jpa.domain.sample.CustomAbstractPersistable + org.springframework.data.jpa.domain.sample.Item + org.springframework.data.jpa.domain.sample.ItemSite org.springframework.data.jpa.domain.sample.MailMessage org.springframework.data.jpa.domain.sample.MailSender org.springframework.data.jpa.domain.sample.MailUser org.springframework.data.jpa.domain.sample.Product org.springframework.data.jpa.domain.sample.Role + org.springframework.data.jpa.domain.sample.Site org.springframework.data.jpa.domain.sample.SpecialUser org.springframework.data.jpa.domain.sample.User org.springframework.data.jpa.domain.sample.Dummy @@ -24,11 +27,14 @@ org.springframework.data.jpa.domain.sample.AuditableRole org.springframework.data.jpa.domain.sample.Category org.springframework.data.jpa.domain.sample.CustomAbstractPersistable + org.springframework.data.jpa.domain.sample.Item + org.springframework.data.jpa.domain.sample.ItemSite org.springframework.data.jpa.domain.sample.MailMessage org.springframework.data.jpa.domain.sample.MailSender org.springframework.data.jpa.domain.sample.MailUser org.springframework.data.jpa.domain.sample.Product org.springframework.data.jpa.domain.sample.Role + org.springframework.data.jpa.domain.sample.Site org.springframework.data.jpa.domain.sample.SpecialUser org.springframework.data.jpa.domain.sample.User org.springframework.data.jpa.domain.sample.Dummy