DATAJPA-12 - Design changes in JpaSort.

Decided to go with a simpler way of building up attribute paths on JpaSort to avoid the need to work with JPA Path instances (and thus the EntityManager) entirely. Added shortcut constructors to JpaSort that take a vararg of Attribute or PluralAttribute respectively.

Interestingly, the test cases still have to be integration tests as the  fields in the statically generated meta-model are null until the EntityManagerFactory bootstrap process enhances them to contain actual values. So no real unit tests unfortunately.

Consolidated tests cases for MailMessageRepository into one class, especially to avoid the configuration QueryDslRepositorySupportIntegrationTests to interfere with the newly added tests. Also rather use SampleConfig configuration class to allow the test framework's caching mechanism to kick in.

Original pull request: #54.
This commit is contained in:
Oliver Gierke
2013-12-07 09:51:00 +01:00
parent 692b2382bf
commit 1d6806b979
6 changed files with 244 additions and 369 deletions

View File

@@ -17,172 +17,114 @@ package org.springframework.data.jpa.domain;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.jpa.support.JpaMetaModelPathBuilder.*;
import static org.springframework.data.jpa.domain.JpaSort.*;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.PluralAttribute;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.sample.Address_;
import org.springframework.data.jpa.domain.sample.MailMessage_;
import org.springframework.data.jpa.domain.sample.MailSender_;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.domain.sample.User_;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Unit test for {@link JpaSort}.
* Integration tests for {@link JpaSort}. This has to be an integration test due to the design of the statically
* generated meta-model classes. The properties cannot be referred to statically (quite a surprise, as they're static)
* but only after they've been enhanced by the persistence provider. This requires an {@link EntityManagerFactory} to be
* bootstrapped.
*
* @see DATAJPA-12
* @author Thomas Darimont
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@ContextConfiguration("classpath:infrastructure.xml")
public class JpaSortTests {
@Configuration
@ImportResource("classpath:infrastructure.xml")
static class Config {}
private static final Attribute<?, ?> NULL_ATTRIBUTE = null;
private static final Attribute<?, ?>[] EMPTY_ATTRIBUTES = new Attribute<?, ?>[0];
@PersistenceContext EntityManager em;
private static final PluralAttribute<?, ?, ?> NULL_PLURAL_ATTRIBUTE = null;
private static final PluralAttribute<?, ?, ?>[] EMPTY_PLURAL_ATTRIBUTES = new PluralAttribute<?, ?, ?>[0];
private static final MailMessage_ jmail = null;
private static final MailSender_ jsender = null;
/**
* @see DATAJPA-12
*/
@Test(expected = IllegalArgumentException.class)
public void shouldThrowIfNoOrderSpecifiersAreGiven() {
new JpaSort();
public void rejectsNullAttribute() {
new JpaSort(NULL_ATTRIBUTE);
}
/**
* @see DATAJPA-12
*/
@Test(expected = IllegalArgumentException.class)
public void shouldThrowIfNullIsGiven() {
new JpaSort((List<Path<?>>) null);
public void rejectsEmptyAttributes() {
new JpaSort(EMPTY_ATTRIBUTES);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullPluralAttribute() {
new JpaSort(NULL_PLURAL_ATTRIBUTE);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsEmptyPluralAttributes() {
new JpaSort(EMPTY_PLURAL_ATTRIBUTES);
}
/**
* @see DATAJPA-12
*/
@Test
public void sortBySinglePropertyWithDefaultSortDirection() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
Root<User> c = q.from(User.class);
JpaSort sort = new JpaSort(c.get("firstname"));
assertThat(sort, hasItems(new Sort.Order("firstname")));
assertThat(new JpaSort(path(User_.firstname)), hasItems(new Sort.Order("firstname")));
}
/**
* @see DATAJPA-12
*/
@Test
public void sortByMultiplePropertiesWithDefaultSortDirection() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
Root<User> c = q.from(User.class);
JpaSort sort = new JpaSort(c.get("firstname"), c.get("lastname"));
assertThat(sort, hasItems(new Sort.Order("firstname"), new Sort.Order("lastname")));
assertThat(new JpaSort(User_.firstname, User_.lastname),
hasItems(new Sort.Order("firstname"), new Sort.Order("lastname")));
}
/**
* @see DATAJPA-12
*/
@Test
public void sortByMultiplePropertiesWithDescSortDirection() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
Root<User> c = q.from(User.class);
JpaSort sort = new JpaSort(Direction.DESC, c.get("firstname"), c.get("lastname"));
assertThat(sort, hasItems(new Sort.Order(Direction.DESC, "firstname"), new Sort.Order(Direction.DESC, "lastname")));
assertThat(new JpaSort(Direction.DESC, User_.firstname, User_.lastname),
hasItems(new Sort.Order(Direction.DESC, "firstname"), new Sort.Order(Direction.DESC, "lastname")));
}
/**
* @see DATAJPA-12
*/
@Test
public void combiningSortByMultipleProperties() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
Root<User> c = q.from(User.class);
Sort sort = new JpaSort(c.get("firstname")).and(new JpaSort(c.get("lastname")));
assertThat(sort, hasItems(new Sort.Order("firstname"), new Sort.Order("lastname")));
assertThat(new JpaSort(User_.firstname).and(new JpaSort(User_.lastname)),
hasItems(new Sort.Order("firstname"), new Sort.Order("lastname")));
}
/**
* @see DATAJPA-12
*/
@Test
public void combiningSortByMultiplePropertiesWithDifferentSort() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
Root<User> c = q.from(User.class);
Sort sort = new JpaSort(c.get("firstname")).and(new JpaSort(Direction.DESC, c.get("lastname")));
assertThat(sort, hasItems(new Sort.Order("firstname"), new Sort.Order(Direction.DESC, "lastname")));
assertThat(new JpaSort(User_.firstname).and(new JpaSort(Direction.DESC, User_.lastname)),
hasItems(new Sort.Order("firstname"), new Sort.Order(Direction.DESC, "lastname")));
}
/**
* @see DATAJPA-12
*/
@Test
public void combiningSortByNestedEmbeddedProperty() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
Root<User> c = q.from(User.class);
Sort sort = new JpaSort(c.get("address").get("streetName"));
assertThat(sort, hasItems(new Sort.Order("address.streetName")));
assertThat(new JpaSort(path(User_.address).dot(Address_.streetName)),
hasItems(new Sort.Order("address.streetName")));
}
/**
* @see DATAJPA-12
*/
@Test
public void buildJpaSortFromJpaMetaModelSingleAttribute() {
Sort sort = new JpaSort(Direction.ASC, path(User_.firstname).build(em));
assertThat(sort, hasItems(new Sort.Order("firstname")));
assertThat(new JpaSort(Direction.ASC, path(User_.firstname)), //
hasItems(new Sort.Order("firstname")));
}
/**
* @see DATAJPA-12
*/
@Test
public void buildJpaSortFromJpaMetaModelNestedAttribute() {
Sort sort = new JpaSort(Direction.ASC, path(MailMessage_.mailSender).get(MailSender_.name).build(em));
assertThat(sort, hasItems(new Sort.Order("mailSender.name")));
assertThat(new JpaSort(Direction.ASC, path(MailMessage_.mailSender).dot(MailSender_.name)),
hasItems(new Sort.Order("mailSender.name")));
}
}

View File

@@ -17,18 +17,13 @@ package org.springframework.data.jpa.repository.support;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.jpa.support.JpaMetaModelPathBuilder.*;
import static org.springframework.data.jpa.domain.JpaSort.*;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
@@ -37,30 +32,27 @@ import org.springframework.data.jpa.domain.sample.MailMessage;
import org.springframework.data.jpa.domain.sample.MailMessage_;
import org.springframework.data.jpa.domain.sample.MailSender;
import org.springframework.data.jpa.domain.sample.MailSender_;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.config.InfrastructureConfig;
import org.springframework.data.jpa.domain.sample.QMailMessage;
import org.springframework.data.jpa.domain.sample.QMailSender;
import org.springframework.data.jpa.repository.sample.MailMessageRepository;
import org.springframework.data.jpa.repository.sample.SampleConfig;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests for {@link MailMessageRepository}.
*
* @author Thomas Darimont
* @author Oliver Gierke
*/
@Transactional
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class JpaMetaModelRepositoryUnitTests {
@ContextConfiguration(classes = SampleConfig.class)
@Transactional
public class MailMessageRepositoryIntegrationTests {
@Configuration
@Import(InfrastructureConfig.class)
@EnableJpaRepositories(basePackageClasses = MailMessageRepository.class)
static class Config {}
private static final MailMessage_ jmail = null;
private static final MailSender_ jsender = null;
@PersistenceContext EntityManager em;
static final QMailMessage message = QMailMessage.mailMessage;
static final QMailSender sender = QMailSender.mailSender;
@Autowired MailMessageRepository mailMessageRepository;
@@ -82,11 +74,35 @@ public class JpaMetaModelRepositoryUnitTests {
mailMessageRepository.save(message2);
Page<MailMessage> results = mailMessageRepository.findAll(new PageRequest(0, 20, //
new JpaSort(Direction.ASC, path(jmail.mailSender).get(jsender.name).build(em))));
new JpaSort(Direction.ASC, path(MailMessage_.mailSender).dot(MailSender_.name))));
List<MailMessage> messages = results.getContent();
assertThat(messages, hasSize(2));
assertThat(messages.get(0).getMailSender(), is(nullValue()));
assertThat(messages.get(1).getMailSender(), is(sender1));
}
/**
* @see DATAJPA-12
*/
@Test
public void shouldSortMailWithQueryDslRepositoryAndDslSortCriteriaNullsFirst() {
MailMessage message1 = new MailMessage();
message1.setContent("abc");
MailSender sender1 = new MailSender("foo");
message1.setMailSender(sender1);
MailMessage message2 = new MailMessage();
message2.setContent("abc");
mailMessageRepository.save(message1);
mailMessageRepository.save(message2);
List<MailMessage> messages = mailMessageRepository.findAll(message.content.eq("abc"), message.mailSender.name.asc());
assertThat(messages, hasSize(2));
assertThat(messages.get(0).getMailSender(), is(nullValue()));
assertThat(messages.get(1).getMailSender(), is(sender1));
}
}

View File

@@ -18,8 +18,6 @@ package org.springframework.data.jpa.repository.support;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@@ -27,21 +25,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.sample.MailMessage;
import org.springframework.data.jpa.domain.sample.MailSender;
import org.springframework.data.jpa.domain.sample.QMailMessage;
import org.springframework.data.jpa.domain.sample.QMailSender;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.config.InfrastructureConfig;
import org.springframework.data.jpa.repository.sample.MailMessageRepository;
import org.springframework.data.jpa.repository.support.QueryDslRepositorySupportTests.UserRepository;
import org.springframework.data.jpa.repository.support.QueryDslRepositorySupportTests.UserRepositoryImpl;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -60,13 +48,10 @@ import org.springframework.transaction.annotation.Transactional;
public class QueryDslRepositorySupportIntegrationTests {
@Configuration
@EnableJpaRepositories(basePackageClasses = MailMessageRepository.class, includeFilters = @Filter(
type = FilterType.ASSIGNABLE_TYPE, value = { MailMessageRepository.class }))
@EnableTransactionManagement
static class Config extends InfrastructureConfig {
@Bean
public UserRepositoryImpl userRepositoryImpl() {
return new UserRepositoryImpl() {
@Override
@PersistenceContext(unitName = "querydsl")
@@ -86,6 +71,7 @@ public class QueryDslRepositorySupportIntegrationTests {
return new EntityManagerContainer();
}
@Override
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
@@ -96,16 +82,10 @@ public class QueryDslRepositorySupportIntegrationTests {
}
@Autowired UserRepository repository;
@Autowired ReconfiguringUserRepositoryImpl reconfiguredRepo;
@Autowired MailMessageRepository mailMessageRepository;
@PersistenceContext(unitName = "querydsl") EntityManager em;
static final QMailMessage qmail = QMailMessage.mailMessage;
static final QMailSender qsender = QMailSender.mailSender;
@Test
public void createsRepoCorrectly() {
assertThat(repository, is(notNullValue()));
@@ -121,56 +101,6 @@ public class QueryDslRepositorySupportIntegrationTests {
assertThat(reconfiguredRepo.getEntityManager().getEntityManagerFactory(), is(em.getEntityManagerFactory()));
}
/**
* @see DATAJPA-12
*/
@Test
public void shouldSortMailWithQueryDslRepositoryAndQPageRequestDslSortCriteriaNullsFirst() {
MailMessage message1 = new MailMessage();
message1.setContent("abc");
MailSender sender1 = new MailSender("foo");
message1.setMailSender(sender1);
MailMessage message2 = new MailMessage();
message2.setContent("abc");
mailMessageRepository.save(message1);
mailMessageRepository.save(message2);
Page<MailMessage> results = mailMessageRepository.findAll(qmail.content.eq("abc"), new QPageRequest(0, 20,
qsender.name.asc()));
List<MailMessage> messages = results.getContent();
assertThat(messages, hasSize(2));
assertThat(messages.get(0).getMailSender(), is(nullValue()));
assertThat(messages.get(1).getMailSender(), is(sender1));
}
/**
* @see DATAJPA-12
*/
@Test
public void shouldSortMailWithQueryDslRepositoryAndDslSortCriteriaNullsFirst() {
MailMessage message1 = new MailMessage();
message1.setContent("abc");
MailSender sender1 = new MailSender("foo");
message1.setMailSender(sender1);
MailMessage message2 = new MailMessage();
message2.setContent("abc");
mailMessageRepository.save(message1);
mailMessageRepository.save(message2);
List<MailMessage> messages = mailMessageRepository.findAll(qmail.content.eq("abc"), qmail.mailSender.name.asc());
assertThat(messages, hasSize(2));
assertThat(messages.get(0).getMailSender(), is(nullValue()));
assertThat(messages.get(1).getMailSender(), is(sender1));
}
static class ReconfiguringUserRepositoryImpl extends QueryDslRepositorySupport {
public ReconfiguringUserRepositoryImpl() {