DATAJPA-50 - Introduced support for usage of @IdClass.

Introduced to support @IdClass to define entity ids. The JpeMetamodelEntityInformation builds instances of the annotated @IdClass in case any of the attributes of the entity declared in the @IdClass has a non-null value.
This commit is contained in:
Oliver Gierke
2012-01-10 10:23:29 +01:00
parent 0795827f8b
commit 3962f1ab31
8 changed files with 460 additions and 48 deletions

View File

@@ -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(SampleWithIdClassPK.class)
public class SampleWithIdClass implements Persistable<SampleWithIdClassPK> {
private static final long serialVersionUID = 1L;
@Id
Long first;
@Id
Long second;
private boolean isNew;
protected SampleWithIdClass() {
this.isNew = true;
}
public SampleWithIdClass(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 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;
}
}

View File

@@ -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 static org.springframework.util.ObjectUtils.*;
import java.io.Serializable;
/**
*
* @author Oliver Gierke
*/
public class SampleWithIdClassPK implements Serializable {
private static final long serialVersionUID = 23126782341L;
private Long first;
private Long second;
public SampleWithIdClassPK() {
}
public SampleWithIdClassPK(Long first, Long second) {
this.first = first;
this.second = second;
}
public void setFirst(Long first) {
this.first = first;
}
public void setSecond(Long second) {
this.second = second;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !(obj.getClass().equals(getClass()))) {
return false;
}
SampleWithIdClassPK that = (SampleWithIdClassPK) obj;
return nullSafeEquals(this.first, that.first) && nullSafeEquals(this.second, that.second);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += nullSafeHashCode(this.first);
result += nullSafeHashCode(this.second);
return result;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-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.
@@ -28,7 +28,10 @@ import javax.persistence.metamodel.Metamodel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.jpa.domain.AbstractPersistable;
import org.springframework.data.jpa.domain.sample.SampleWithIdClass;
import org.springframework.data.jpa.domain.sample.SampleWithIdClassPK;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -62,4 +65,31 @@ public class JpaMetamodelEntityInformationIntegrationTests {
JpaEntityInformation<?, ?> information = JpaEntityInformationSupport.getMetadata(AbstractPersistable.class, em);
assertEquals(Serializable.class, information.getIdType());
}
/**
* @see DATAJPA-50
*/
@Test
public void detectsIdClass() {
EntityInformation<SampleWithIdClass, ?> information = JpaEntityInformationSupport.getMetadata(
SampleWithIdClass.class, em);
assertThat(information.getIdType(), is(typeCompatibleWith(SampleWithIdClassPK.class)));
}
/**
* @see DATAJPA-50
*/
@Test
public void returnsIdInstanceCorrectly() {
SampleWithIdClass entity = new SampleWithIdClass(2L, 4L);
JpaEntityInformation<SampleWithIdClass, ?> information = JpaEntityInformationSupport.getMetadata(
SampleWithIdClass.class, em);
Object id = information.getId(entity);
assertThat(id, is(SampleWithIdClassPK.class));
assertThat(id, is((Object) new SampleWithIdClassPK(2L, 4L)));
}
}

View File

@@ -0,0 +1,92 @@
/*
* 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.repository.support;
import static java.util.Arrays.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import org.junit.Before;
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;
/**
* Unit tests for {@link JpaMetamodelEntityInformation}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class JpaMetamodelEntityInformationUnitTest {
@Mock
Metamodel metamodel;
@Mock
IdentifiableType<SampleWithIdClass> type;
@Mock
SingularAttribute<SampleWithIdClass, ?> first, second;
@Mock
@SuppressWarnings("rawtypes")
Type idType;
@Before
@SuppressWarnings("unchecked")
public void setUp() {
when(first.getName()).thenReturn("first");
when(second.getName()).thenReturn("second");
Set<SingularAttribute<? super SampleWithIdClass, ?>> attributes = new HashSet<SingularAttribute<? super SampleWithIdClass, ?>>(
asList(first, second));
when(type.getIdClassAttributes()).thenReturn(attributes);
when(metamodel.managedType(SampleWithIdClass.class)).thenReturn(type);
when(type.getIdType()).thenReturn(idType);
when(idType.getJavaType()).thenReturn(SampleWithIdClassPK.class);
}
/**
* @see DATAJPA-50
*/
@Test
public void doesNotCreateIdIfAllPartialAttributesAreNull() {
JpaMetamodelEntityInformation<SampleWithIdClass, Serializable> information = new JpaMetamodelEntityInformation<SampleWithIdClass, Serializable>(
SampleWithIdClass.class, metamodel);
SampleWithIdClass entity = new SampleWithIdClass(null, null);
assertThat(information.getId(entity), is(nullValue()));
entity = new SampleWithIdClass(2L, null);
assertThat(information.getId(entity), is(notNullValue()));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2011 the original author or authors.
* Copyright 2008-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.
@@ -28,7 +28,10 @@ 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.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@@ -47,11 +50,13 @@ public class JpaRepositoryTests {
EntityManager em;
JpaRepository<SampleEntity, SampleEntityPK> repository;
CrudRepository<SampleWithIdClass, SampleWithIdClassPK> idClassRepository;
@Before
public void setUp() {
repository = new JpaRepositoryFactory(em).getRepository(SampleEntityRepository.class);
idClassRepository = new JpaRepositoryFactory(em).getRepository(SampleWithIdClassRepository.class);
}
@Test
@@ -68,7 +73,28 @@ public class JpaRepositoryTests {
assertThat(repository.count(), is(0L));
}
/**
* DATAJPA-50
*/
@Test
public void executesCrudOperationsForEntityWithIdClass() {
SampleWithIdClass entity = new SampleWithIdClass(1L, 1L);
idClassRepository.save(entity);
assertThat(entity.getFirst(), is(notNullValue()));
assertThat(entity.getSecond(), is(notNullValue()));
SampleWithIdClassPK id = new SampleWithIdClassPK(entity.getFirst(), entity.getSecond());
assertThat(idClassRepository.findOne(id), is(entity));
}
private static interface SampleEntityRepository extends JpaRepository<SampleEntity, SampleEntityPK> {
}
private static interface SampleWithIdClassRepository extends CrudRepository<SampleWithIdClass, SampleWithIdClassPK> {
}
}