Initial commit of Spring JPA repository abstraction.

Port of the Hades project whereas the JPA independent part resides in Spring Data Commons Core. Reflect changes refactorings for DATACMNS-2, DATACMNS-3, DATACMNS-4, DATACMNS-5, DATACMNS-6, DATACMNS-8, DATACMNS-9, DATAJPA-2.
This commit is contained in:
Oliver Gierke
2010-11-07 18:47:38 +01:00
parent 85e588d7d0
commit e8c5666070
109 changed files with 9957 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
package org.springframework.data.jpa.domain.sample;
import javax.persistence.Entity;
import org.springframework.data.jpa.domain.AbstractPersistable;
/**
* @author Oliver Gierke
*/
@Entity
public class Account extends AbstractPersistable<Long> {
private static final long serialVersionUID = -5719129808165758887L;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2008-2010 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 org.springframework.data.jpa.domain.AbstractAuditable;
/**
* Sample auditable role entity.
*
* @author Oliver Gierke
*/
@Entity
public class AuditableRole extends AbstractAuditable<AuditableUser, Long> {
private static final long serialVersionUID = 5997359055260303863L;
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2008-2010 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.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQuery;
import org.springframework.data.jpa.domain.AbstractAuditable;
/**
* Sample auditable user to demonstrate working with
* {@code AbstractAuditableEntity}. No declaration of an ID is necessary.
* Furthermore no auditing information has to be declared explicitly.
*
* @author Oliver Gierke
*/
@Entity
@NamedQuery(name = "AuditableUser.findByFirstname", query = "SELECT u FROM AuditableUser u WHERE u.firstname = ?1")
public class AuditableUser extends AbstractAuditable<AuditableUser, Long> {
private static final long serialVersionUID = 7409344446795693011L;
private String firstname;
@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private Set<AuditableRole> roles = new HashSet<AuditableRole>();
public AuditableUser() {
this(null);
}
public AuditableUser(Long id) {
this.setId(id);
}
/**
* Returns the firstname.
*
* @return the firstname
*/
public String getFirstname() {
return firstname;
}
/**
* Sets the firstname.
*
* @param firstname the firstname to set
*/
public void setFirstname(final String firstname) {
this.firstname = firstname;
}
public void addRole(AuditableRole role) {
this.roles.add(role);
}
public Set<AuditableRole> getRoles() {
return roles;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2008-2010 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 org.springframework.data.domain.AuditorAware;
/**
* Stub implementation for {@link AuditorAware}. Returns {@literal null} for the
* current auditor.
*
* @author Oliver Gierke
*/
public class AuditorAwareStub implements AuditorAware<User> {
/*
* (non-Javadoc)
*
* @see org.synyx.hades.domain.auditing.AuditorAware#getCurrentAuditor()
*/
public User getCurrentAuditor() {
return null;
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2008-2010 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.GenerationType;
import javax.persistence.Id;
/**
* Example implementation of the very basic {@code Persistable} interface. The
* id type is matching the typisation of the interface.
* {@code Persitsable#isNew()} is implemented regarding the id as flag.
*
* @author Oliver Gierke
*/
@Entity
public class Role {
private static final long serialVersionUID = -8832631113344035104L;
private static final String PREFIX = "ROLE_";
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
/**
* Creates a new instance of {@code Role}.
*/
public Role() {
}
/**
* Creates a new preconfigured {@code Role}.
*
* @param name
*/
public Role(final String name) {
this.name = name;
}
/*
* (non-Javadoc)
*
* @see org.synyx.hades.jpa.support.Entity#getId()
*/
public Integer getId() {
return id;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return PREFIX + name;
}
/*
* (non-Javadoc)
*
* @see org.synyx.hades.jpa.support.Entity#isNew()
*/
public boolean isNew() {
return id == null;
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2008-2010 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.EmbeddedId;
import javax.persistence.Entity;
/**
* @author Oliver Gierke
*/
@Entity
public class SampleEntity {
@EmbeddedId
protected SampleEntityPK id;
protected SampleEntity() {
}
public SampleEntity(String first, String second) {
this.id = new SampleEntityPK(first, second);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!getClass().equals(obj.getClass())) {
return false;
}
SampleEntity that = (SampleEntity) obj;
return this.id.equals(that.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2008-2010 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.Column;
import javax.persistence.Embeddable;
import org.springframework.util.Assert;
@Embeddable
public class SampleEntityPK implements Serializable {
private static final long serialVersionUID = 231060947L;
@Column(nullable = false)
private String first;
@Column(nullable = false)
private String second;
public SampleEntityPK() {
this.first = null;
this.second = null;
}
public SampleEntityPK(String first, String second) {
Assert.notNull(first);
Assert.notNull(second);
this.first = first;
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 (!this.getClass().equals(obj.getClass())) {
return false;
}
SampleEntityPK that = (SampleEntityPK) obj;
return this.first.equals(that.first) && this.second.equals(that.second);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * first.hashCode();
result += 31 * second.hashCode();
return result;
}
}

View File

@@ -0,0 +1,278 @@
/*
* Copyright 2008-2010 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.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQuery;
/**
* Domain class representing a person emphasizing the use of
* {@code AbstractEntity}. No declaration of an id is required. The id is typed
* by the parameterizable superclass.
*
* @author Oliver Gierke
*/
@Entity
@NamedQuery(name = "User.findByEmailAddress", query = "SELECT u FROM User u WHERE u.emailAddress = ?1")
public class User {
private static final long serialVersionUID = 8653688953355455933L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String firstname;
private String lastname;
@Column(nullable = false, unique = true)
private String emailAddress;
@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
private Set<User> colleagues;
@ManyToMany
private Set<Role> roles;
/**
* Creates a new empty instance of {@code User}.
*/
public User() {
this.roles = new HashSet<Role>();
this.colleagues = new HashSet<User>();
}
/**
* Creates a new instance of {@code User} with preinitialized values for
* firstname, lastname and email address.
*
* @param firstname
* @param lastname
* @param emailAddress
*/
public User(final String firstname, final String lastname,
final String emailAddress) {
this();
this.firstname = firstname;
this.lastname = lastname;
this.emailAddress = emailAddress;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* Returns the firstname.
*
* @return the firstname
*/
public String getFirstname() {
return firstname;
}
/**
* Sets the firstname.
*
* @param firstname the firstname to set
*/
public void setFirstname(final String firstname) {
this.firstname = firstname;
}
/**
* Returns the lastname.
*
* @return the lastname
*/
public String getLastname() {
return lastname;
}
/**
* Sets the lastname.
*
* @param lastname the lastname to set
*/
public void setLastname(String lastname) {
this.lastname = lastname;
}
/**
* Returns the email address.
*
* @return the emailAddress
*/
public String getEmailAddress() {
return emailAddress;
}
/**
* Sets the email address.
*
* @param emailAddress the emailAddress to set
*/
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
/**
* Returns the user's roles.
*
* @return the role
*/
public Set<Role> getRole() {
return roles;
}
/**
* Gives the user a role. Adding a role the user already owns is a no-op.
*/
public void addRole(Role role) {
roles.add(role);
}
/**
* Revokes a role from a user.
*
* @param role
*/
public void removeRole(Role role) {
roles.remove(role);
}
/**
* Returns the colleagues of the user.
*
* @return the colleagues
*/
public Set<User> getColleagues() {
return colleagues;
}
/**
* Adds a new colleague to the user. Adding the user himself as colleague is
* a no-op.
*
* @param collegue
*/
public void addColleague(User collegue) {
// Prevent from adding the user himself as colleague.
if (this.equals(collegue)) {
return;
}
colleagues.add(collegue);
collegue.getColleagues().add(this);
}
/**
* Removes a colleague from the list of colleagues.
*
* @param colleague
*/
public void removeColleague(User colleague) {
colleagues.remove(colleague);
colleague.getColleagues().remove(this);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof User)) {
return false;
}
User that = (User) obj;
if (null == this.getId() || null == that.getId()) {
return false;
}
return this.getId().equals(that.getId());
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "User: " + getId() + ", " + getFirstname() + " " + getLastname()
+ ", " + getEmailAddress();
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2008-2010 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.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
/**
* Collection of {@link Specification}s for a {@link User}.
*
* @author Oliver Gierke
*/
public class UserSpecifications {
/**
* A {@link Specification} to match on a {@link User}'s firstname.
*
* @param firstname
* @return
*/
public static Specification<User> userHasFirstname(final String firstname) {
return simplePropertySpec("firstname", firstname);
}
/**
* A {@link Specification} to match on a {@link User}'s lastname.
*
* @param firstname
* @return
*/
public static Specification<User> userHasLastname(final String lastname) {
return simplePropertySpec("lastname", lastname);
}
private static <T> Specification<T> simplePropertySpec(
final String property, final Object value) {
return new Specification<T>() {
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
return builder.equal(root.get(property), value);
}
};
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2008-2010 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.support;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.jpa.domain.support.AuditingBeanFactoryPostProcessor;
/**
* Unit test for {@link AuditingBeanFactoryPostProcessor}.
*
* @author Oliver Gierke
*/
public class AuditingBeanFactoryPostProcessorUnitTests {
ConfigurableListableBeanFactory beanFactory;
AuditingBeanFactoryPostProcessor processor;
@Before
public void setUp() {
beanFactory =
new XmlBeanFactory(new ClassPathResource("auditing/"
+ getConfigFile()));
processor = new AuditingBeanFactoryPostProcessor();
}
protected String getConfigFile() {
return "auditing-bfpp-context.xml";
}
@Test
public void testname() throws Exception {
processor.postProcessBeanFactory(beanFactory);
BeanDefinition definition =
beanFactory.getBeanDefinition("entityManagerFactory");
assertTrue(Arrays
.asList(definition.getDependsOn())
.contains(
AuditingBeanFactoryPostProcessor.BEAN_CONFIGURER_ASPECT_BEAN_NAME));
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2008-2010 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.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Auditable;
import org.springframework.data.jpa.domain.sample.AuditableRole;
import org.springframework.data.jpa.domain.sample.AuditableUser;
import org.springframework.data.jpa.repository.sample.AuditableUserRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:auditing/auditing-entity-listener.xml")
public class AuditingEntityListenerTests {
@Autowired
AuditableUserRepository dao;
@Test
public void auditsRootEntityCorrectly() throws Exception {
AuditableUser user = new AuditableUser();
dao.save(user);
assertDatesSet(user);
}
@Test
public void auditsTransitiveEntitiesCorrectly() throws Exception {
AuditableRole role = new AuditableRole();
role.setName("ADMIN");
AuditableUser user = new AuditableUser();
user.addRole(role);
dao.save(user);
assertDatesSet(user);
assertDatesSet(role);
}
private void assertDatesSet(Auditable<?, ?> auditable) {
assertThat(auditable.getCreatedDate(), is(notNullValue()));
assertThat(auditable.getLastModifiedDate(), is(notNullValue()));
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2008-2010 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.support;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.domain.sample.AuditableUser;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* Unit test for {@code AuditingEntityListener}.
*
* @author Oliver Gierke
*/
@SuppressWarnings("unchecked")
public class AuditingEntityListenerUnitTests {
AuditingEntityListener<AuditableUser> auditionAdvice;
AuditorAware<AuditableUser> auditorAware;
AuditableUser user;
@Before
public void setUp() {
auditionAdvice = new AuditingEntityListener<AuditableUser>();
user = new AuditableUser();
auditorAware = mock(AuditorAware.class);
when(auditorAware.getCurrentAuditor()).thenReturn(user);
}
/**
* Checks that the advice does not set auditor on the target entity if no
* {@code AuditorAware} was configured.
*/
@Test
public void doesNotSetAuditorIfNotConfigured() {
auditionAdvice.touch(user);
assertNotNull(user.getCreatedDate());
assertNotNull(user.getLastModifiedDate());
assertNull(user.getCreatedBy());
assertNull(user.getLastModifiedBy());
}
/**
* Checks that the advice sets the auditor on the target entity if an
* {@code AuditorAware} was configured.
*/
@Test
public void setsAuditorIfConfigured() {
auditionAdvice.setAuditorAware(auditorAware);
auditionAdvice.touch(user);
assertNotNull(user.getCreatedDate());
assertNotNull(user.getLastModifiedDate());
assertNotNull(user.getCreatedBy());
assertNotNull(user.getLastModifiedBy());
verify(auditorAware).getCurrentAuditor();
}
/**
* Checks that the advice does not set modification information on creation
* if the falg is set to {@code false}.
*/
@Test
public void honoursModifiedOnCreationFlag() {
auditionAdvice.setAuditorAware(auditorAware);
auditionAdvice.setModifyOnCreation(false);
auditionAdvice.touch(user);
assertNotNull(user.getCreatedDate());
assertNotNull(user.getCreatedBy());
assertNull(user.getLastModifiedBy());
assertNull(user.getLastModifiedDate());
verify(auditorAware).getCurrentAuditor();
}
/**
* Tests that the advice only sets modification data if a not-new entity is
* handled.
*/
@Test
public void onlySetsModificationDataOnNotNewEntities() {
user = new AuditableUser(1L);
auditionAdvice.setAuditorAware(auditorAware);
auditionAdvice.touch(user);
assertNull(user.getCreatedBy());
assertNull(user.getCreatedDate());
assertNotNull(user.getLastModifiedBy());
assertNotNull(user.getLastModifiedDate());
verify(auditorAware).getCurrentAuditor();
}
@Test
public void doesNotSetTimeIfConfigured() throws Exception {
auditionAdvice.setDateTimeForNow(false);
auditionAdvice.setAuditorAware(auditorAware);
auditionAdvice.touch(user);
assertNotNull(user.getCreatedBy());
assertNull(user.getCreatedDate());
assertNotNull(user.getLastModifiedBy());
assertNull(user.getLastModifiedDate());
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2008-2010 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.support;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* Unit test for the Hades {@code auditing} namespace element.
*
* @author Oliver Gierke
*/
public class AuditingNamespaceUnitTests extends
AuditingBeanFactoryPostProcessorUnitTests {
/*
* (non-Javadoc)
*
* @see
* org.synyx.hades.domain.auditing.AuditingBeanFactoryPostProcessorUnitTest
* #getConfigFile()
*/
@Override
protected String getConfigFile() {
return "auditing-namespace-context.xml";
}
@Test
public void registersBeanDefinitions() throws Exception {
BeanDefinition definition =
beanFactory.getBeanDefinition(AuditingEntityListener.class
.getName());
assertEquals(
definition.getPropertyValues().getPropertyValue("auditorAware")
.getValue(), new RuntimeBeanReference("auditorAware"));
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2008-2010 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.junit.Ignore;
/**
* Testcase to run {@link org.synyx.hades.dao.UserDao} integration tests on top
* of EclipseLink. So far not running as of an EclipseLink bug.
*
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=312132
* @author Oliver Gierke
*/
// @ContextConfiguration(value = "classpath:eclipselink.xml", inheritLocations =
// true)
@Ignore
public class EclipseLinkNamespaceUserRepositoryTests extends
NamespaceUserRepositoryTests {
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2008-2010 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.junit.Assert.*;
import java.util.Map;
import org.junit.Test;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
import org.springframework.test.context.ContextConfiguration;
/**
* Use namespace context to run tests. Checks for existence of required
* PostProcessors, too.
*
* @author Oliver Gierke
* @author Eberhard Wolff
*/
@ContextConfiguration(locations = "classpath:config/namespace-application-context.xml", inheritLocations = false)
public class NamespaceUserRepositoryTests extends UserRepositoryTests {
@Autowired
ListableBeanFactory beanFactory;
@Test
public void registersPostProcessors() {
hasAtLeastOneBeanOfType(PersistenceAnnotationBeanPostProcessor.class);
hasAtLeastOneBeanOfType(PersistenceExceptionTranslationPostProcessor.class);
}
private void hasAtLeastOneBeanOfType(Class<?> beanType) {
Map<String, ?> beans = beanFactory.getBeansOfType(beanType);
assertFalse(beans.entrySet().isEmpty());
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2008-2010 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.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Simple test case launching an {@code ApplicationContext} to test
* infrastructure configuration.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:infrastructure.xml")
public class ORMInfrastructureTests {
@Autowired
ApplicationContext context;
/**
* Tests, that the context got initialized and injected correctly.
*
* @throws Exception
*/
@Test
public void contextInitialized() throws Exception {
assertNotNull(context);
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2008-2010 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.test.context.ContextConfiguration;
/**
* Testcase to run {@link org.synyx.hades.dao.UserDao} integration tests on top
* of OpenJPA.
*
* @author Oliver Gierke
*/
@ContextConfiguration(value = "classpath:openjpa.xml", inheritLocations = true)
public class OpenJpaNamespaceUserDaoTests extends
NamespaceUserRepositoryTests {
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2008-2010 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.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration test for executing finders, thus testing various query lookup
* strategies.
*
* @see QueryLookupStrategy
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:config/namespace-application-context.xml")
@Transactional
public class UserRepositoryFinderTests {
@Autowired
UserRepository userRepository;
User firstUser, secondUser;
@Before
public void setUp() {
// This one matches both criterias
firstUser = new User();
firstUser.setEmailAddress("foo");
firstUser.setLastname("bar");
firstUser.setFirstname("foobar");
userRepository.save(firstUser);
// This one matches only the second one
secondUser = new User();
secondUser.setEmailAddress("bar");
secondUser.setLastname("foo");
userRepository.save(secondUser);
}
/**
* Tests creation of a simple query.
*/
@Test
public void testSimpleCustomCreatedFinder() {
User user = userRepository.findByEmailAddressAndLastname("foo", "bar");
assertEquals(firstUser, user);
}
/**
* Tests that the DAO returns {@code null} for not found objects for finder
* methods that return a single domain object.
*/
@Test
public void returnsNullIfNothingFound() {
User user = userRepository.findByEmailAddress("foobar");
assertEquals(null, user);
}
/**
* Tests creation of a simple query consisting of {@code AND} and {@code OR}
* parts.
*/
@Test
public void testAndOrFinder() {
List<User> users =
userRepository.findByEmailAddressAndLastnameOrFirstname("bar",
"foo", "foobar");
assertNotNull(users);
assertEquals(2, users.size());
assertTrue(users.contains(firstUser));
assertTrue(users.contains(secondUser));
}
@Test
public void executesPagingMethodToPageCorrectly() throws Exception {
Page<User> page =
userRepository
.findByFirstname(new PageRequest(0, 20), "foobar");
assertEquals(1, page.getNumberOfElements());
}
@Test
public void executesPagingMethodToListCorrectly() throws Exception {
List<User> list =
userRepository
.findByFirstname("foobar", new PageRequest(0, 20));
assertThat(list.size(), is(1));
}
}

View File

@@ -0,0 +1,699 @@
/*
* Copyright 2008-2010 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 static org.springframework.data.domain.Sort.Direction.*;
import static org.springframework.data.jpa.domain.Specifications.*;
import static org.springframework.data.jpa.domain.sample.UserSpecifications.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.sample.Role;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Base integration test class for {@code UserRepository}. Loads a basic
* (non-namespace) Spring configuration file as well as Hibernate configuration
* to execute tests.
* <p>
* To test further persistence providers subclass this class and provide a
* custom provider configuration.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:application-context.xml" })
@Transactional
public class UserRepositoryTests {
@PersistenceContext
EntityManager em;
// CUT
@Autowired
UserRepository repository;
// Test fixture
User firstUser, secondUser, thirdUser;
Integer id;
@Before
public void setUp() {
firstUser = new User("Oliver", "Gierke", "gierke@synyx.de");
secondUser = new User("Joachim", "Arrasz", "arrasz@synyx.de");
thirdUser = new User("Dave", "Matthews", "no@email.com");
}
/**
* Tests creation of users.
*/
@Test
public void testCreation() {
Query countQuery = em.createQuery("select count(u) from User u");
Long before = (Long) countQuery.getSingleResult();
flushTestUsers();
assertEquals(before + 3, countQuery.getSingleResult());
}
/**
* Tests reading a single user.
*
* @throws Exception
*/
@Test
public void testRead() throws Exception {
flushTestUsers();
User foundPerson = repository.findById(id);
assertEquals(firstUser.getFirstname(), foundPerson.getFirstname());
}
/**
* Asserts, that a call to {@code UserRepository#readId(Integer)} returns
* {@code null} for invalid not {@code null} ids.
*/
@Test
public void testReadByIdReturnsNullForNotFoundEntities() {
flushTestUsers();
assertNull(repository.findById(id * 27));
}
@Test
public void savesCollectionCorrectly() throws Exception {
List<User> result =
repository
.save(Arrays.asList(firstUser, secondUser, thirdUser));
assertNotNull(result);
assertThat(result.size(), is(3));
assertThat(result, hasItems(firstUser, secondUser, thirdUser));
}
@Test
public void savingNullCollectionIsNoOp() throws Exception {
List<User> result = repository.save((Collection<User>) null);
assertNotNull(result);
assertTrue(result.isEmpty());
}
@Test
public void savingEmptyCollectionIsNoOp() throws Exception {
List<User> result = repository.save(new ArrayList<User>());
assertNotNull(result);
assertTrue(result.isEmpty());
}
/**
* Tests updating a user.
*/
@Test
public void testUpdate() {
flushTestUsers();
User foundPerson = repository.findById(id);
foundPerson.setLastname("Schlicht");
User updatedPerson = repository.findById(id);
assertEquals(foundPerson.getFirstname(), updatedPerson.getFirstname());
}
@Test
public void existReturnsWhetherAnEntityCanBeLoaded() throws Exception {
flushTestUsers();
assertTrue(repository.exists(id));
assertFalse(repository.exists(id * 27));
}
/**
* Tests deleting a user.
*/
@Test
public void testDelete() {
flushTestUsers();
repository.delete(firstUser);
assertNull(repository.findById(id));
}
@Test
public void returnsAllSortedCorrectly() throws Exception {
flushTestUsers();
List<User> result = repository.findAll(new Sort(ASC, "lastname"));
assertNotNull(result);
assertThat(result.size(), is(3));
assertThat(result.get(0), is(secondUser));
assertThat(result.get(1), is(firstUser));
assertThat(result.get(2), is(thirdUser));
}
@Test
public void deleteColletionOfEntities() {
flushTestUsers();
long before = repository.count();
repository.delete(Arrays.asList(firstUser, secondUser));
assertThat(repository.count(), is(before - 2));
}
@Test
public void deleteEmptyCollectionDoesNotDeleteAnything() {
assertDeleteCallDoesNotDeleteAnything(new ArrayList<User>());
}
@Test
public void deleteWithNullDoesNotDeleteAnything() throws Exception {
assertDeleteCallDoesNotDeleteAnything(null);
}
private void assertDeleteCallDoesNotDeleteAnything(List<User> collection) {
flushTestUsers();
Long count = repository.count();
repository.delete(collection);
assertEquals(count, repository.count());
}
@Test
public void executesManipulatingQuery() throws Exception {
flushTestUsers();
repository.renameAllUsersTo("newLastname");
assertEquals(repository.count().intValue(),
repository.findByLastname("newLastname").size());
}
/**
* Make sure no {@link NullPointerException} is being thrown.
*
* @see Ticket #110
*/
@Test
public void testFinderInvocationWithNullParameter() {
flushTestUsers();
repository.findByLastname(null);
}
/**
* Tests, that searching by the lastname of the reference user returns
* exactly that instance.
*
* @throws Exception
*/
@Test
public void testFindByLastname() throws Exception {
flushTestUsers();
List<User> byName = repository.findByLastname("Gierke");
assertTrue(byName.size() == 1);
assertEquals(firstUser, byName.get(0));
}
/**
* Tests, that searching by the email address of the reference user returns
* exactly that instance.
*
* @throws Exception
*/
@Test
public void testFindByEmailAddress() throws Exception {
flushTestUsers();
User byName = repository.findByEmailAddress("gierke@synyx.de");
assertNotNull(byName);
assertEquals(firstUser, byName);
}
/**
* Tests reading all users.
*/
@Test
public void testReadAll() {
flushTestUsers();
List<User> reference = Arrays.asList(firstUser, secondUser);
assertTrue(repository.findAll().containsAll(reference));
}
/**
* Tests that all users get deleted by triggering
* {@link UserDao#deleteAll()}.
*
* @throws Exception
*/
@Test
public void deleteAll() throws Exception {
flushTestUsers();
repository.deleteAll();
assertEquals((Long) 0L, repository.count());
}
/**
* Tests cascading persistence.
*/
@Test
public void testCascadesPersisting() {
// Create link prior to persisting
firstUser.addColleague(secondUser);
// Persist
flushTestUsers();
// Fetches first user from .. bdatabase
User firstReferenceUser = repository.findById(firstUser.getId());
assertEquals(firstUser, firstReferenceUser);
// Fetch colleagues and assert link
Set<User> colleagues = firstReferenceUser.getColleagues();
assertEquals(1, colleagues.size());
assertTrue(colleagues.contains(secondUser));
}
/**
* Tests, that persisting a relationsship without cascade attributes throws
* a {@code DataAccessException}.
*/
@Test(expected = DataAccessException.class)
public void testPreventsCascadingRolePersisting() {
firstUser.addRole(new Role("USER"));
flushTestUsers();
}
/**
* Tests cascading on {@literal merge} operation.
*/
@Test
public void testMergingCascadesCollegueas() {
firstUser.addColleague(secondUser);
flushTestUsers();
firstUser.addColleague(new User("Florian", "Hopf", "hopf@synyx.de"));
firstUser = repository.save(firstUser);
User reference = repository.findById(firstUser.getId());
Set<User> colleagues = reference.getColleagues();
assertNotNull(colleagues);
assertEquals(2, colleagues.size());
}
/**
* Tests, that the generic dao implements count correctly.
*/
@Test
public void testCountsCorrectly() {
Long count = repository.count();
User user = new User();
user.setEmailAddress("gierke@synyx.de");
repository.save(user);
assertTrue(repository.count().equals(count + 1));
}
/**
* Tests invoking a method of a custom implementation of the DAO interface.
*/
@Test
public void testInvocationOfCustomImplementation() {
repository.someCustomMethod(new User());
}
/**
* Tests that overriding a finder method is recognized by the DAO
* implementation. If an overriding method is found it will will be invoked
* instead of the automatically generated finder.
*/
@Test
public void testOverwritingFinder() {
repository.findByOverrridingMethod();
}
@Test
public void testUsesHadesQueryAnnotation() {
assertEquals(null, repository.findByHadesQuery("gierke@synyx.de"));
}
@Test
public void testExecutionOfProjectingMethod() {
flushTestUsers();
assertEquals(1, repository.countWithFirstname("Oliver").longValue());
}
@Test
public void executesSpecificationCorrectly() {
flushTestUsers();
assertThat(
repository.findAll(where(userHasFirstname("Oliver"))).size(),
is(1));
}
@Test
public void executesSingleEntitySpecificationCorrectly() throws Exception {
flushTestUsers();
assertThat(repository.findOne(userHasFirstname("Oliver")),
is(firstUser));
}
@Test
public void executesCombinedSpecificationsCorrectly() {
flushTestUsers();
Specification<User> spec =
where(userHasFirstname("Oliver")).or(userHasLastname("Arrasz"));
assertThat(repository.findAll(spec).size(), is(2));
}
@Test
public void executesCombinedSpecificationsWithPageableCorrectly() {
flushTestUsers();
Specification<User> spec =
where(userHasFirstname("Oliver")).or(userHasLastname("Arrasz"));
Page<User> users = repository.findAll(spec, new PageRequest(0, 1));
assertThat(users.getSize(), is(1));
assertThat(users.hasPreviousPage(), is(false));
assertThat(users.getTotalElements(), is(2L));
}
/**
* Flushes test users to the database.
*/
private void flushTestUsers() {
firstUser = repository.save(firstUser);
secondUser = repository.save(secondUser);
thirdUser = repository.save(thirdUser);
repository.flush();
id = firstUser.getId();
assertThat(id, is(notNullValue()));
assertThat(secondUser.getId(), is(notNullValue()));
assertThat(thirdUser.getId(), is(notNullValue()));
assertThat(repository.exists(id), is(true));
assertThat(repository.exists(secondUser.getId()), is(true));
assertThat(repository.exists(thirdUser.getId()), is(true));
}
@Test
public void executesMethodWithAnnotatedNamedParametersCorrectly()
throws Exception {
firstUser = repository.save(firstUser);
secondUser = repository.save(secondUser);
assertTrue(repository.findByLastnameOrFirstname("Oliver", "Arrasz")
.containsAll(Arrays.asList(firstUser, secondUser)));
}
@Test
@Ignore
public void executesMethodWithNamedParametersCorrectly() throws Exception {
firstUser = repository.save(firstUser);
secondUser = repository.save(secondUser);
assertThat(repository.findByLastnameOrFirstnameUnannotated("Oliver",
"Arrasz"), hasItems(firstUser, secondUser));
}
@Test
public void executesMethodWithNamedParametersCorrectlyOnMethodsWithQueryCreation()
throws Exception {
firstUser = repository.save(firstUser);
secondUser = repository.save(secondUser);
assertTrue(repository.findByFirstnameOrLastname("Oliver", "Arrasz")
.containsAll(Arrays.asList(firstUser, secondUser)));
}
@Test
public void executesLikeAndOrderByCorrectly() throws Exception {
flushTestUsers();
List<User> result =
repository.findByLastnameLikeOrderByFirstnameDesc("%r%");
assertEquals(firstUser, result.get(0));
assertEquals(secondUser, result.get(1));
}
@Test
public void executesNotLikeCorrectly() throws Exception {
flushTestUsers();
List<User> result = repository.findByLastnameNotLike("%er%");
assertThat(result.size(), is(2));
assertThat(result, hasItems(secondUser, thirdUser));
}
@Test
public void executesSimpleNotCorrectly() throws Exception {
flushTestUsers();
List<User> result = repository.findByLastnameNot("Gierke");
assertThat(result.size(), is(2));
assertThat(result, hasItems(secondUser, thirdUser));
}
@Test
public void returnsSameListIfNoSpecGiven() throws Exception {
flushTestUsers();
assertSameElements(repository.findAll(),
repository.findAll((Specification<User>) null));
}
@Test
public void returnsSameListIfNoSortIsGiven() throws Exception {
flushTestUsers();
assertSameElements(repository.findAll((Sort) null),
repository.findAll());
}
@Test
public void returnsSamePageIfNoSpecGiven() throws Exception {
Pageable pageable = new PageRequest(0, 1);
flushTestUsers();
assertEquals(repository.findAll(pageable),
repository.findAll(null, pageable));
}
@Test
public void returnsAllAsPageIfNoPageableIsGiven() throws Exception {
flushTestUsers();
assertEquals(new PageImpl<User>(repository.findAll()),
repository.findAll((Pageable) null));
}
private static <T> void assertSameElements(Collection<T> first,
Collection<T> second) {
for (T element : first) {
assertThat(element, isIn(second));
}
for (T element : second) {
assertThat(element, isIn(first));
}
}
@Test
public void removeDetachedObject() throws Exception {
flushTestUsers();
em.detach(firstUser);
repository.delete(firstUser);
assertThat(repository.count(), is(2L));
}
@Test
@SuppressWarnings("unchecked")
public void executesPagedSpecificationsCorrectly() throws Exception {
Page<User> result = executeSpecWithSort(null);
assertThat(result.getContent(),
anyOf(hasItem(firstUser), hasItem(thirdUser)));
assertThat(result.getContent(), not(hasItem(secondUser)));
}
@Test
public void executesPagedSpecificationsWithSortCorrectly() throws Exception {
Page<User> result =
executeSpecWithSort(new Sort(Direction.ASC, "lastname"));
assertThat(result.getContent(), hasItem(firstUser));
assertThat(result.getContent(), not(hasItem(secondUser)));
assertThat(result.getContent(), not(hasItem(thirdUser)));
}
@Test
public void executesPagedSpecificationWithSortCorrectly2() throws Exception {
Page<User> result =
executeSpecWithSort(new Sort(Direction.DESC, "lastname"));
assertThat(result.getContent(), hasItem(thirdUser));
assertThat(result.getContent(), not(hasItem(secondUser)));
assertThat(result.getContent(), not(hasItem(firstUser)));
}
private Page<User> executeSpecWithSort(Sort sort) {
flushTestUsers();
Specification<User> spec =
where(userHasFirstname("Oliver")).or(
userHasLastname("Matthews"));
Page<User> result =
repository.findAll(spec, new PageRequest(0, 1, sort));
assertThat(result.getTotalElements(), is(2L));
return result;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2008-2010 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.config;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.sample.AuditableUserRepository;
import org.springframework.data.jpa.repository.sample.RoleRepository;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Abstract base class for integration test for namespace configuration.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
public abstract class AbstractRepositoryConfigTests {
@Autowired(required = false)
UserRepository userRepository;
@Autowired(required = false)
RoleRepository roleRepository;
@Autowired(required = false)
AuditableUserRepository auditableUserRepository;
/**
* Asserts that context creation detects 3 DAO beans.
*/
@Test
public void testContextCreation() {
assertNotNull(userRepository);
assertNotNull(roleRepository);
assertNotNull(auditableUserRepository);
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2008-2010 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.config;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.custom.UserCustomExtendedRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;
/**
* Annotation to exclude DAO interfaces from being picked up by Hades and thus
* in consequence getting an instance being created.
* <p>
* This will typically be used when providing an extended base interface for all
* DAOs in combination with a custom DAO base class to implement methods
* declared in that intermediate interface. In this case you typically derive
* your concrete DAO interfaces from the intermediate one but don't want Hades
* to create a Spring bean for the intermediate interface.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:config/namespace-customfactory-context.xml")
public class CustomRepositoryFactoryConfigTests {
@Autowired(required = false)
UserCustomExtendedRepository userRepository;
@Test(expected = UnsupportedOperationException.class)
public void testCustomFactoryUsed() {
Assert.notNull(userRepository);
userRepository.customMethod(1);
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2008-2010 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.config;
import static org.junit.Assert.*;
import static org.springframework.test.util.ReflectionTestUtils.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Integration test for XML configuration of {@link QueryLookupStrategy.Key}s.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:config/lookup-strategies-context.xml")
public class QueryLookupStrategyTests {
@Autowired
ApplicationContext context;
/**
* Assert that {@link QueryLookupStrategy#USE_DECLARED_QUERY} is being set
* on the factory if configured.
*/
@Test
public void assertUseDeclaredQuery() {
JpaRepositoryFactoryBean<?> factory =
context.getBean("&roleRepository",
JpaRepositoryFactoryBean.class);
assertEquals(Key.USE_DECLARED_QUERY,
getField(factory, "queryLookupStrategyKey"));
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2008-2010 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.config;
import org.springframework.test.context.ContextConfiguration;
/**
* Integration test to test DAO auto configuration.
*
* @author Oliver Gierke
*/
@ContextConfiguration(locations = "classpath:config/namespace-autoconfig-context.xml")
public class RepositoryAutoConfigTests extends
AbstractRepositoryConfigTests {
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008-2010 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.config;
import org.springframework.test.context.ContextConfiguration;
/**
* Integration test for DAO namespace configuration.
*
* @author Oliver Gierke
*/
@ContextConfiguration(locations = "classpath:config/namespace-application-context.xml")
public class RepositoryConfigTests extends AbstractRepositoryConfigTests {
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2008-2010 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.config;
import static org.junit.Assert.*;
import org.springframework.test.context.ContextConfiguration;
/**
* Integration test to test
* {@link org.springframework.core.type.filter.TypeFilter} integration into
* namespace.
*
* @author Oliver Gierke
*/
@ContextConfiguration(locations = "classpath:config/namespace-autoconfig-typefilter-context.xml")
public class TypeFilterConfigTest extends
AbstractRepositoryConfigTests {
/*
* (non-Javadoc)
*
* @seeorg.synyx.hades.dao.config.AbstractDaoConfigIntegrationTest#
* testContextCreation()
*/
@Override
public void testContextCreation() {
assertNotNull(userRepository);
assertNotNull(roleRepository);
assertNull(auditableUserRepository);
}
}

View File

@@ -0,0 +1,4 @@
<html>
<head></head>
<body>Test cases for configuration support classes.</body>
</html>

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2008-2010 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.custom;
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
/**
* Sample custom DAO base class implementing common custom functionality for all
* derived DAO instances.
*
* @author Oliver Gierke
*/
public class CustomGenericJpaRepository<T, ID extends Serializable> extends
SimpleJpaRepository<T, ID> implements CustomGenericRepository<T, ID> {
/**
* @param domainClass
* @param entityManager
*/
public CustomGenericJpaRepository(Class<T> domainClass,
EntityManager entityManager) {
super(domainClass, entityManager);
}
/*
* (non-Javadoc)
*
* @see
* org.synyx.hades.customimpl.CustomExtendedGenericDao#customMethod(java
* .io.Serializable)
*/
public T customMethod(ID id) {
throw new UnsupportedOperationException(
"Forced exception for testing purposes.");
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2008-2010 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.custom;
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.repository.support.RepositorySupport;
/**
* Sample implementation of a custom {@link JpaRepositoryFactory} to use
* a custom repository base class.
*
* @author Oliver Gierke
*/
public class CustomGenericJpaRepositoryFactory extends
JpaRepositoryFactory {
/**
* @param entityManager
*/
public CustomGenericJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.jpa.repository.support.GenericJpaRepositoryFactory
* #getTargetRepository(java.lang.Class, javax.persistence.EntityManager)
*/
@Override
protected <T, ID extends Serializable> RepositorySupport<T, ID> getTargetRepository(
Class<T> domainClass, EntityManager em) {
return new CustomGenericJpaRepository<T, ID>(domainClass, em);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.jpa.repository.support.GenericJpaRepositoryFactory
* #getRepositoryClass()
*/
@Override
@SuppressWarnings("rawtypes")
protected Class<? extends RepositorySupport> getRepositoryClass() {
return CustomGenericJpaRepository.class;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2008-2010 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.custom;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.support.RepositoryFactorySupport;
/**
* {@link GenericDaoFactoryBean} to return a custom DAO base class.
*
* @author Gil Markham
* @author Oliver Gierke
*/
public class CustomGenericJpaRepositoryFactoryBean<T extends JpaRepository<?, ?>>
extends JpaRepositoryFactoryBean<T> {
/*
* (non-Javadoc)
*
* @see org.springframework.data.jpa.repository.support.
* GenericJpaRepositoryFactoryBean#getFactory()
*/
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
return new CustomGenericJpaRepositoryFactory(em);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2008-2010 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.custom;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.NoRepositoryBean;
/**
* Extension of {@link Repository} to be added on a custom repository
* base class. This tests the facility to implement custom base class
* functionality for all repository instances derived from this interface and
* implementation base class.
*
* @author Oliver Gierke
*/
@NoRepositoryBean
public interface CustomGenericRepository<T, ID extends Serializable> extends
JpaRepository<T, ID> {
/**
* Custom sample method.
*
* @param id
* @return
*/
T customMethod(ID id);
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2008-2010 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.custom;
import org.springframework.data.jpa.domain.sample.User;
/**
* Custom Extended DAO interface for a {@code User}. This relies on the custom
* intermediate DAO interface {@link CustomGenericRepository}.
*
* @author Oliver Gierke
*/
public interface UserCustomExtendedRepository extends CustomGenericRepository<User, Integer> {
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright 2008-2010 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.query;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
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.repository.query.JpaQueryExecution.ModifyingExecution;
/**
* Unit test for {@link QueryExecution}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class JpaQueryExecutionUnitTests {
@Mock
EntityManager em;
@Mock
AbstractJpaQuery jpaQuery;
@Mock
ParameterBinder binder;
@Mock
Query query;
Method method;
@Before
public void setUp() throws Exception {
method = Dummy.class.getMethod("voidMethod");
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullQuery() {
new StubQueryExecution().execute(null, binder);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullBinder() throws Exception {
new StubQueryExecution().execute(jpaQuery, null);
}
@Test
public void transformsNoResultExceptionToNull() {
assertThat(new JpaQueryExecution() {
@Override
protected Object doExecute(AbstractJpaQuery query,
ParameterBinder binder) {
throw new NoResultException();
}
}.execute(jpaQuery, binder), is(nullValue()));
}
@Test
public void modifyingExecutionClearsEntityManagerIfSet() {
Query param = any();
when(binder.bind(param)).thenReturn(query);
when(query.executeUpdate()).thenReturn(0);
ModifyingExecution execution = new ModifyingExecution(method, em);
execution.execute(jpaQuery, binder);
verify(em, times(1)).clear();
}
@Test
public void allowsMethodReturnTypesForModifyingQuery() throws Exception {
new ModifyingExecution(Dummy.class.getMethod("voidMethod"), em);
new ModifyingExecution(Dummy.class.getMethod("intMethod"), em);
new ModifyingExecution(Dummy.class.getMethod("integerMethod"), em);
}
@Test(expected = IllegalArgumentException.class)
public void modifyingExecutionRejectsNonIntegerOrVoidReturnType()
throws Exception {
new ModifyingExecution(Dummy.class.getMethod("longMethod"), em);
}
static class StubQueryExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query,
ParameterBinder binder) {
return null;
}
}
static interface Dummy {
void voidMethod();
int intMethod();
Integer integerMethod();
Long longMethod();
}
}

View File

@@ -0,0 +1,288 @@
/*
* Copyright 2008-2010 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.query;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.QueryHint;
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.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.query.JpaQueryExecution.CollectionExecution;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.repository.query.QueryMethod;
/**
* Unit test for {@link QueryMethod}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class JpaQueryMethodUnitTests {
static final Class<?> DOMAIN_CLASS = User.class;
static final String METHOD_NAME = "findByFirstname";
@Mock
QueryExtractor extractor;
@Mock
EntityManager em;
Method daoMethod, invalidReturnType, pageableAndSort, pageableTwice,
sortableTwice, modifyingMethod;
/**
* @throws Exception
*/
@Before
public void setUp() throws Exception {
daoMethod =
UserRepository.class.getMethod("findByLastname", String.class);
invalidReturnType =
InvalidDao.class.getMethod(METHOD_NAME, String.class,
Pageable.class);
pageableAndSort =
InvalidDao.class.getMethod(METHOD_NAME, String.class,
Pageable.class, Sort.class);
pageableTwice =
InvalidDao.class.getMethod(METHOD_NAME, String.class,
Pageable.class, Pageable.class);
sortableTwice =
InvalidDao.class.getMethod(METHOD_NAME, String.class,
Sort.class, Sort.class);
modifyingMethod =
UserRepository.class
.getMethod("renameAllUsersTo", String.class);
}
@Test
public void testname() {
JpaQueryMethod method = new JpaQueryMethod(daoMethod, extractor, em);
assertEquals("User.findByLastname", method.getNamedQueryName());
assertThat(method.getExecution(), is(CollectionExecution.class));
assertEquals("select x from User x where x.lastname = ?1",
new QueryCreator(method).constructQuery());
}
@Test(expected = IllegalArgumentException.class)
public void preventsNullDaoMethod() {
new JpaQueryMethod(null, extractor, em);
}
@Test(expected = IllegalArgumentException.class)
public void preventsNullEntityManager() {
new JpaQueryMethod(daoMethod, extractor, null);
}
@Test(expected = IllegalArgumentException.class)
public void preventsNullQueryExtractor() {
new JpaQueryMethod(daoMethod, null, em);
}
@Test
public void returnsCorrectName() {
JpaQueryMethod method = new JpaQueryMethod(daoMethod, extractor, em);
assertEquals(daoMethod.getName(), method.getName());
}
@Test
public void returnsQueryIfAvailable() throws Exception {
JpaQueryMethod method = new JpaQueryMethod(daoMethod, extractor, em);
assertNull(method.getAnnotatedQuery());
Method daoMethod =
UserRepository.class
.getMethod("findByHadesQuery", String.class);
assertNotNull(new JpaQueryMethod(daoMethod, extractor, em)
.getAnnotatedQuery());
}
@Test
public void returnsCorrectDomainClassName() {
JpaQueryMethod method = new JpaQueryMethod(daoMethod, extractor, em);
assertEquals(DOMAIN_CLASS, method.getDomainClass());
}
@Test
public void returnsCorrectNumberOfParameters() {
JpaQueryMethod method = new JpaQueryMethod(daoMethod, extractor, em);
assertTrue(method.isCorrectNumberOfParameters(daoMethod
.getParameterTypes().length));
}
@Test(expected = IllegalStateException.class)
public void rejectsInvalidReturntypeOnPagebleFinder() {
new JpaQueryMethod(invalidReturnType, extractor, em);
}
@Test(expected = IllegalStateException.class)
public void rejectsPageableAndSortInFinderMethod() {
new JpaQueryMethod(pageableAndSort, extractor, em);
}
@Test(expected = IllegalStateException.class)
public void rejectsTwoPageableParameters() {
new JpaQueryMethod(pageableTwice, extractor, em);
}
@Test(expected = IllegalStateException.class)
public void rejectsTwoSortableParameters() {
new JpaQueryMethod(sortableTwice, extractor, em);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsPageablesOnPersistenceProvidersNotExtractingQueries()
throws Exception {
Method method =
UserRepository.class.getMethod("findByFirstname",
Pageable.class, String.class);
when(extractor.canExtractQuery()).thenReturn(false);
new JpaQueryMethod(method, extractor, em);
}
@Test
public void recognizesModifyingMethod() {
JpaQueryMethod method =
new JpaQueryMethod(modifyingMethod, extractor, em);
assertTrue(method.isModifyingQuery());
}
@Test(expected = IllegalArgumentException.class)
public void rejectsModifyingMethodWithPageable() throws Exception {
Method method =
InvalidDao.class.getMethod("updateMethod", String.class,
Pageable.class);
new JpaQueryMethod(method, extractor, em);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsModifyingMethodWithSort() throws Exception {
Method method =
InvalidDao.class.getMethod("updateMethod", String.class,
Sort.class);
new JpaQueryMethod(method, extractor, em);
}
@Test
public void discoversHintsCorrectly() {
JpaQueryMethod method = new JpaQueryMethod(daoMethod, extractor, em);
List<QueryHint> hints = method.getHints();
assertNotNull(hints);
assertThat(hints.get(0).name(), is("foo"));
assertThat(hints.get(0).value(), is("bar"));
}
/**
* Interface to define invalid DAO methods for testing.
*
* @author Oliver Gierke
*/
static interface InvalidDao {
// Invalid return type
User findByFirstname(String firstname, Pageable pageable);
// Should not use Pageable *and* Sort
Page<User> findByFirstname(String firstname, Pageable pageable,
Sort sort);
// Must not use two Pageables
Page<User> findByFirstname(String firstname, Pageable first,
Pageable second);
// Must not use two Pageables
Page<User> findByFirstname(String firstname, Sort first, Sort second);
// Not backed by a named query or @Query annotation
@Modifying
void updateMethod(String firstname);
// Modifying and Pageable is not allowed
@Modifying
Page<String> updateMethod(String firstname, Pageable pageable);
// Modifying and Sort is not allowed
@Modifying
void updateMethod(String firstname, Sort sort);
}
}

View File

@@ -0,0 +1,207 @@
/*
* Copyright 2008-2010 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.query;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import javax.persistence.Query;
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.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.QueryCreatorUnitTests.SampleEmbeddable;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.query.Parameters;
/**
* Unit test for {@link ParameterBinder}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class ParameterBinderUnitTests {
private Method valid;
@Mock
private Query query;
private Method useIndexedParameters;
private Method indexedParametersWithSort;
@Before
public void setUp() throws SecurityException, NoSuchMethodException {
valid = SampleDao.class.getMethod("valid", String.class);
useIndexedParameters =
SampleDao.class.getMethod("useIndexedParameters", String.class);
indexedParametersWithSort =
SampleDao.class.getMethod("indexedParameterWithSort",
String.class, Sort.class);
}
static class User {
}
static interface SampleDao {
User useIndexedParameters(String lastname);
User indexedParameterWithSort(String lastname, Sort sort);
User valid(@Param("username") String username);
User validWithPageable(@Param("username") String username,
Pageable pageable);
User validWithSort(@Param("username") String username, Sort sort);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsToManyParameters() throws Exception {
new ParameterBinder(new Parameters(valid),
new Object[] { "foo", "bar" });
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullParameters() throws Exception {
new ParameterBinder(new Parameters(valid), (Object[]) null);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsToLittleParameters() throws SecurityException,
NoSuchMethodException {
Parameters parameters = new Parameters(valid);
new ParameterBinder(parameters);
}
@Test
public void returnsNullIfNoPageableWasProvided() throws SecurityException,
NoSuchMethodException {
Method method =
SampleDao.class.getMethod("validWithPageable", String.class,
Pageable.class);
Parameters parameters = new Parameters(method);
ParameterBinder binder =
new ParameterBinder(parameters, new Object[] { "foo", null });
assertThat(binder.getPageable(), is(nullValue()));
}
@Test
public void bindWorksWithNullForSort() throws Exception {
Method validWithSort =
SampleDao.class.getMethod("validWithSort", String.class,
Sort.class);
new ParameterBinder(new Parameters(validWithSort), new Object[] {
"foo", null }).bind(query);
verify(query).setParameter(eq(1), eq("foo"));
}
@Test
public void bindWorksWithNullForPageable() throws Exception {
Method validWithPageable =
SampleDao.class.getMethod("validWithPageable", String.class,
Pageable.class);
new ParameterBinder(new Parameters(validWithPageable), new Object[] {
"foo", null }).bind(query);
verify(query).setParameter(eq(1), eq("foo"));
}
@Test
public void usesIndexedParametersIfNoParamAnnotationPresent()
throws Exception {
new ParameterBinder(new Parameters(useIndexedParameters),
new Object[] { "foo" }).bind(query);
verify(query).setParameter(eq(1), anyObject());
}
@Test
public void usesParameterNameIfAnnotated() throws Exception {
when(query.setParameter(eq("username"), anyObject())).thenReturn(query);
new ParameterBinder(new Parameters(valid), new Object[] { "foo" }) {
@Override
boolean hasNamedParameter(Query query) {
return true;
}
}.bind(query);
verify(query).setParameter(eq("username"), anyObject());
}
@Test
public void bindsEmbeddableCorrectly() throws Exception {
Method method =
QueryCreatorUnitTests.class.getMethod("findByEmbeddable",
SampleEmbeddable.class);
Parameters parameters = new Parameters(method);
SampleEmbeddable embeddable = new SampleEmbeddable();
new ParameterBinder(parameters, new Object[] { embeddable })
.bind(query);
verify(query).setParameter(1, embeddable);
}
@Test
public void bindsSortForIndexedParameters() throws Exception {
Sort sort = new Sort("name");
ParameterBinder binder =
new ParameterBinder(new Parameters(indexedParametersWithSort),
new Object[] { "name", sort });
assertThat(binder.getSort(), is(sort));
}
}

View File

@@ -0,0 +1,327 @@
/*
* Copyright 2008-2010 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.query;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.util.Date;
import javax.persistence.Embeddable;
import javax.persistence.EntityManager;
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.User;
import org.springframework.data.jpa.repository.query.JpaQueryMethodUnitTests.InvalidDao;
import org.springframework.data.repository.query.QueryCreationException;
/**
* Unit test for {@link QueryCreator}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class QueryCreatorUnitTests {
private Method method;
@Mock
QueryExtractor extractor;
@Mock
EntityManager em;
@Before
public void setup() throws SecurityException, NoSuchMethodException {
method =
QueryCreatorUnitTests.class.getMethod(
"findByFirstnameAndMethod", String.class);
}
@Test(expected = QueryCreationException.class)
public void rejectsInvalidProperty() throws Exception {
JpaQueryMethod finderMethod = new JpaQueryMethod(method, extractor, em);
new QueryCreator(finderMethod).constructQuery();
}
@Test
public void splitsKeywordsCorrectly() throws SecurityException,
NoSuchMethodException {
method =
QueryCreatorUnitTests.class.getMethod(
"findByNameOrOrganization", String.class, String.class);
assertCreatesQueryForMethod(
"where x.name = :name or x.organization = :organization",
method);
}
/**
* @throws NoSuchMethodException
* @throws SecurityException
* @see #265
* @throws Exception
*/
@Test
public void createsQueryWithEmbeddableCorrectly() throws SecurityException,
NoSuchMethodException {
method =
getClass()
.getMethod("findByEmbeddable", SampleEmbeddable.class);
assertCreatesQueryForMethod("where x.embeddable = :embeddable", method);
}
@Test
public void createsQueryWithBetweenKeywordCorrectly() throws Exception {
method =
getClass().getMethod("findByStartDateBetweenAndName",
Date.class, Date.class, String.class);
assertCreatesQueryForMethod(
"where x.startDate between :first and :second and x.name = :name",
method);
}
@Test
public void createsQueryWithLessThanKeywordCorrectly() throws Exception {
method = getClass().getMethod("findByAgeLessThan", int.class);
assertCreatesQueryForMethod("where x.age < :age", method);
}
@Test
public void createsQueryWithGreaterThanKeywordCorrectly() throws Exception {
method = getClass().getMethod("findByAgeGreaterThan", int.class);
assertCreatesQueryForMethod("where x.age > :age", method);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsModifyingMethodWithoutBacking()
throws SecurityException, NoSuchMethodException {
Method invalidModifyingMethod =
InvalidDao.class.getMethod("updateMethod", String.class);
JpaQueryMethod method =
new JpaQueryMethod(invalidModifyingMethod, extractor, em);
new QueryCreator(method);
}
@Test
public void parsesLikeOperatorCorrectly() throws Exception {
method = getClass().getMethod("findByNameLike", String.class);
assertCreatesQueryForMethod("where x.name like :name", method);
}
@Test
public void parsesNotOperatorCorrectly() throws Exception {
method = getClass().getMethod("findByNameNot", String.class);
assertCreatesQueryForMethod("where x.name <> :name", method);
}
@Test
public void parsesNotNullOperatorCorrectly() throws Exception {
method = getClass().getMethod("findByNameNotNull");
assertCreatesQueryForMethod("where x.name is not null", method);
}
@Test
public void parsesLikeCorrectly() throws Exception {
method = getClass().getMethod("findByNameLike", String.class);
assertCreatesQueryForMethod("where x.name like :name", method);
}
@Test
public void parsesNotLikeCorrectly() throws Exception {
method = getClass().getMethod("findByNameNotLike", String.class);
assertCreatesQueryForMethod("where x.name not like :name", method);
}
@Test
public void parsesOrderByClauseCorrectly() throws Exception {
method =
getClass().getMethod("findByNameOrderByOrganizationDesc",
String.class);
assertCreatesQueryForMethod(
"where x.name = :name order by x.organization desc", method);
}
/**
* Asserts that the query created for the given {@link Method} results in a
* query ending with the given {@link String}.
*
* @param queryEnd
* @param method
*/
private void assertCreatesQueryForMethod(String queryEnd, Method method) {
JpaQueryMethod queryMethod = new JpaQueryMethod(method, extractor, em);
String result = new QueryCreator(queryMethod).constructQuery();
assertThat(result, endsWith(queryEnd));
}
/**
* Sample method to test failing query creation.
*
* @param firstname
* @return
*/
public User findByFirstnameAndMethod(String firstname) {
return null;
}
/**
* A method to check that query keyowrds are considered correctly. The
* {@link QueryCreator} must not detect the {@code Or} in
* {@code Organization} as keyword.
*
* @param name
* @param organization
* @return
*/
public SampleEntity findByNameOrOrganization(String name,
String organization) {
return null;
}
/**
* Sample method to create a finder query for that references an
* {@link Embeddable}.
*
* @see #265
* @param embeddable
* @return
*/
public SampleEntity findByEmbeddable(SampleEmbeddable embeddable) {
return null;
}
public SampleEntity findByStartDateBetweenAndName(Date first, Date second,
String name) {
return null;
}
public SampleEntity findByAgeLessThan(int age) {
return null;
}
public SampleEntity findByAgeGreaterThan(int age) {
return null;
}
public SampleEntity findByNameLike(String name) {
return null;
}
public SampleEntity findByNameNotLike(String name) {
return null;
}
public SampleEntity findByNameNot(String name) {
return null;
}
public SampleEntity findByNameNotNull() {
return null;
}
public SampleEntity findByNameOrderByOrganizationDesc(String name) {
return null;
}
/**
* Sample class for keyword split check.
*
* @author Oliver Gierke
*/
@SuppressWarnings("unused")
static class SampleEntity {
private String organization;
private String name;
private Date startDate;
private int age;
private SampleEmbeddable embeddable;
}
@Embeddable
@SuppressWarnings("unused")
static class SampleEmbeddable {
private String foo;
private String bar;
}
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright 2008-2010 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.query;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.jpa.repository.query.QueryUtils.*;
import org.hamcrest.Matcher;
import org.junit.Test;
/**
* Unit test for {@link QueryUtils}.
*
* @author Oliver Gierke
*/
public class QueryUtilsUnitTests {
static final String QUERY = "select u from User u";
static final String FQ_QUERY =
"select u from org.synyx.hades.domain.User$Foo_Bar u";
static final String SIMPLE_QUERY = "from User u";
static final String COUNT_QUERY = "select count(u) from User u";
static final String QUERY_WITH_AS =
"select u from User as u where u.username = ?";
static final Matcher<String> IS_U = is("u");
@Test
public void createsCountQueryCorrectly() throws Exception {
assertCountQuery(QUERY, COUNT_QUERY);
}
/**
* @see #303
*/
@Test
public void createsCountQueriesCorrectlyForCapitalLetterJPQL() {
assertCountQuery("FROM User u WHERE u.foo.bar = ?",
"select count(u) FROM User u WHERE u.foo.bar = ?");
assertCountQuery("SELECT u FROM User u where u.foo.bar = ?",
"select count(u) FROM User u where u.foo.bar = ?");
}
/**
* @see #351
*/
@Test
public void createsCountQueryForDistinctQueries() throws Exception {
assertCountQuery("select distinct u from User u where u.foo = ?",
"select count(distinct u) from User u where u.foo = ?");
}
/**
* @see #351
*/
@Test
public void createsCountQueryForConstructorQueries() throws Exception {
assertCountQuery(
"select distinct new User(u.name) from User u where u.foo = ?",
"select count(distinct u) from User u where u.foo = ?");
}
/**
* @see #352
*/
@Test
public void createsCountQueryForJoins() throws Exception {
assertCountQuery(
"select distinct new User(u.name) from User u left outer join u.roles r WHERE r = ?",
"select count(distinct u) from User u left outer join u.roles r WHERE r = ?");
}
/**
* @see #352
*/
@Test
public void createsCountQueryForQueriesWithSubSelects() throws Exception {
assertCountQuery(
"select u from User u left outer join u.roles r where r in (select r from Role)",
"select count(u) from User u left outer join u.roles r where r in (select r from Role)");
}
/**
* @see #355
*/
@Test
public void createsCountQueryForAliasesCorrectly() throws Exception {
assertCountQuery("select u from User as u",
"select count(u) from User as u");
}
@Test
public void allowsShortJpaSyntax() throws Exception {
assertCountQuery(SIMPLE_QUERY, COUNT_QUERY);
}
@Test
public void detectsAliasCorrectly() throws Exception {
assertThat(detectAlias(QUERY), IS_U);
assertThat(detectAlias(SIMPLE_QUERY), IS_U);
assertThat(detectAlias(COUNT_QUERY), IS_U);
assertThat(detectAlias(QUERY_WITH_AS), IS_U);
assertThat(detectAlias("SELECT FROM USER U"), is("U"));
assertThat(detectAlias("select u from User u"), IS_U);
assertThat(detectAlias("select u from com.acme.User u"), IS_U);
}
@Test
public void allowsFullyQualifiedEntityNamesInQuery() {
assertThat(detectAlias(FQ_QUERY), IS_U);
assertCountQuery(FQ_QUERY,
"select count(u) from org.synyx.hades.domain.User$Foo_Bar u");
}
private void assertCountQuery(String originalQuery, String countQuery) {
assertThat(createCountQueryFor(originalQuery), is(countQuery));
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2008-2010 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.query;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.QueryHint;
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.repository.QueryHints;
import org.springframework.data.jpa.repository.sample.UserRepository;
/**
* Unit test for {@link SimpleHadesQuery}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class SimpleJpaQueryUnitTests {
private JpaQueryMethod method;
@Mock
private EntityManager em;
@Mock
private QueryExtractor extractor;
@Mock
private Query query;
@Before
@QueryHints(@QueryHint(name = "foo", value = "bar"))
public void setUp() throws SecurityException, NoSuchMethodException {
when(em.createQuery(anyString())).thenReturn(query);
Method setUp =
UserRepository.class.getMethod("findByLastname", String.class);
method = new JpaQueryMethod(setUp, extractor, em);
}
@Test
public void appliesHintsCorrectly() throws Exception {
SimpleJpaQuery hadesQuery = new SimpleJpaQuery(method, em, "foobar");
hadesQuery.createQuery(em, new ParameterBinder(method.getParameters(),
new Object[] { "gierke" }));
verify(query).setHint("foo", "bar");
}
@Test
public void prefersDeclaredCountQueryOverCreatingOne() throws Exception {
method = mock(JpaQueryMethod.class);
when(method.getCountQuery()).thenReturn("foo");
when(em.createQuery("foo")).thenReturn(query);
SimpleJpaQuery hadesQuery =
new SimpleJpaQuery(method, em, "select u from User u");
assertThat(hadesQuery.createCountQuery(em), is(query));
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2008-2010 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 java.util.List;
import org.springframework.data.jpa.domain.sample.AuditableUser;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* DAO interface for {@code AuditableUser}.
*
* @author Oliver Gierke
*/
public interface AuditableUserRepository extends
JpaRepository<AuditableUser, Long> {
/**
* Returns all users with the given firstname.
*
* @param firstname
* @return all users with the given firstname.
*/
public List<AuditableUser> findByFirstname(final String firstname);
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2008-2010 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.Role;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* Typing interface for {@code Role}.
*
* @author Oliver Gierke
*/
public interface RoleRepository extends JpaRepository<Role, Integer> {
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright 2008-2010 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 java.util.List;
import javax.persistence.QueryHint;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
/**
* DAO interface for {@code User}s. The declared methods will trigger named
* queries as they start with {@code findBy}.
*
* @author Oliver Gierke
*/
public interface UserRepository extends JpaRepository<User, Integer>,
UserRepositoryCustom {
/**
* Retrieve users by their lastname. The finder
* {@literal User.findByLastname} is declared in {@literal META-INF/orm.xml}
* .
*
* @param lastname
* @return all users with the given lastname
*/
@QueryHints({ @QueryHint(name = "foo", value = "bar") })
List<User> findByLastname(String lastname);
/**
* Redeclaration of {@link Repository#findById(java.io.Serializable)} to
* change transaction configuration.
*/
@Transactional
public User findById(Integer primaryKey);
/**
* Retrieve users by their email address. The finder
* {@literal User.findByEmailAddress} is declared as annotation at
* {@code User}.
*
* @param emailAddress
* @return the user with the given email address
*/
User findByEmailAddress(String emailAddress);
@Query("select u from User u ")
Page<User> findAllPaged(Pageable pageable);
/**
* Retrieves users by the given email and lastname. Acts as a dummy method
* declaration to test finder query creation.
*
* @param emailAddress
* @param lastname
* @return the user with the given email address and lastname
*/
User findByEmailAddressAndLastname(String emailAddress, String lastname);
/**
* Retrieves users by email address and lastname or firstname. Acts as a
* dummy method declaration to test finder query creation.
*
* @param emailAddress
* @param lastname
* @param username
* @return the users with the given email address and lastname or the given
* firstname
*/
List<User> findByEmailAddressAndLastnameOrFirstname(String emailAddress,
String lastname, String username);
/**
* Retrieves a user by its username using the query annotated to the method.
*
* @param username
* @return
*/
@Query("select u from User u where u.emailAddress = ?1")
@Transactional(readOnly = true)
User findByHadesQuery(String emailAddress);
/**
* Method to directly create query from and adding a {@link Pageable}
* parameter to be regarded on query execution.
*
* @param pageable
* @param firstname
* @return
*/
Page<User> findByFirstname(Pageable pageable, String firstname);
/**
* Method to directly create query from and adding a {@link Pageable}
* parameter to be regarded on query execution. Just returns the queried
* {@link Page}'s contents.
*
* @param firstname
* @param pageable
* @return
*/
List<User> findByFirstname(String firstname, Pageable pageable);
/**
* Manipulating query to set all {@link User}'s names to the given one.
*
* @param lastname
*/
@Modifying
@Query("update User u set u.lastname = ?1")
void renameAllUsersTo(String lastname);
@Query("select count(u) from User u where u.firstname = ?1")
Long countWithFirstname(String firstname);
/**
* Method where parameters will be applied by name. Note that the order of
* the parameters is then not crucial anymore.
*
* @param firstname
* @param lastname
* @return
*/
@Query("select u from User u where u.lastname = :lastname or u.firstname = :firstname")
List<User> findByLastnameOrFirstname(@Param("firstname") String foo,
@Param("lastname") String bar);
@Query("select u from User u where u.lastname = :lastname or u.firstname = :firstname")
List<User> findByLastnameOrFirstnameUnannotated(String firstname,
String lastname);
/**
* Method to check query creation and named parameter usage go well hand in
* hand.
*
* @param lastname
* @param firstname
* @return
*/
List<User> findByFirstnameOrLastname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
List<User> findByLastnameLikeOrderByFirstnameDesc(String lastname);
List<User> findByLastnameNotLike(String lastname);
List<User> findByLastnameNot(String lastname);
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2008-2010 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.User;
/**
* Simple interface for custom methods on the DAO for {@code User}s.
*
* @author Oliver Gierke
*/
public interface UserRepositoryCustom {
/**
* Method actually triggering a finder but being overridden.
*/
void findByOverrridingMethod();
/**
* Some custom method to implement.
*
* @param user
*/
void someCustomMethod(User user);
}

View File

@@ -0,0 +1,34 @@
package org.springframework.data.jpa.repository.sample;
import org.springframework.data.jpa.domain.sample.User;
/**
* Dummy implementation to allow check for invoking a custom implementation.
*
* @author Oliver Gierke
*/
public class UserRepositoryImpl implements UserRepositoryCustom {
/*
* (non-Javadoc)
*
* @see
* org.synyx.hades.dao.UserDao#someOtherMethod(org.synyx.hades.domain.User)
*/
public void someCustomMethod(User u) {
System.out.println("Some custom method was invoked!");
}
/*
* (non-Javadoc)
*
* @see org.synyx.hades.dao.UserDaoCustom#findFooMethod()
*/
public void findByOverrridingMethod() {
System.out.println("A mthod overriding a finder was invoked!");
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2008-2010 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 javax.persistence.EntityManagerFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.sample.AuditableUser;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.sample.AuditableUserRepository;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Assures the injected DAO instances are wired to the customly configured
* {@link EntityManagerFactory}.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:multiple-entity-manager-integration-context.xml")
public class EntityManagerFactoryRefTests {
@Autowired
UserRepository userRepository;
@Autowired
AuditableUserRepository auditableUserDao;
@Test
@Transactional
public void useUserRepository() throws Exception {
userRepository.saveAndFlush(new User("firstname", "lastname",
"foo@bar.de"));
}
@Test
@Transactional("transactionManager-2")
public void useAuditableUserDao() throws Exception {
auditableUserDao.saveAndFlush(new AuditableUser());
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2008-2010 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 org.mockito.Mockito.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.hibernate.ejb.HibernateEntityManager;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.jpa.repository.config.AbstractRepositoryConfigTests;
import org.springframework.orm.jpa.EntityManagerFactoryInfo;
import org.springframework.test.context.ContextConfiguration;
/**
* Assures the injected DAO instances are wired to the customly configured
* {@link EntityManagerFactory}.
*
* @author Oliver Gierke
*/
@ContextConfiguration(locations = "classpath:multiple-entity-manager-context.xml")
public class EntityManagerFactoryRefUnitTests extends
AbstractRepositoryConfigTests {
@Autowired
@Qualifier("entityManagerFactory")
EntityManagerFactory first;
@Autowired
@Qualifier("secondEntityManagerFactory")
EntityManagerFactory second;
@Test
public void daosGetTheSecondEntityManagerFactoryInjected() throws Exception {
verify(first, never()).createEntityManager();
verify(second, atLeastOnce()).createEntityManager();
}
/**
* A simple No-Op {@link PersistenceExceptionTranslator} to be configured in
* the test case's config file as it is required.
*
* @author Oliver Gierke
*/
static class NoOpPersistenceExceptionTranslator implements
PersistenceExceptionTranslator {
public DataAccessException translateExceptionIfPossible(
RuntimeException ex) {
return null;
}
}
/**
* {@link BeanPostProcessor} to configure the mock
* {@link EntityManagerFactory} instances. {@code entityManagerFactory} is
* configured to be never invoked, {@code secondEntityManagerFactory} is
* configured to be invoked at least once.
*
* @author Oliver Gierke
*/
static class MockPreparingBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
if ("secondEntityManagerFactory".equals(beanName)) {
EntityManagerFactory entityManagerFactory =
(EntityManagerFactory) bean;
EntityManager em = mock(HibernateEntityManager.class);
when(entityManagerFactory.createEntityManager()).thenReturn(em);
EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) bean;
when(info.getEntityManagerInterface()).thenAnswer(
new Answer<Class<?>>() {
public Class<?> answer(InvocationOnMock invocation)
throws Throwable {
return HibernateEntityManager.class;
}
});
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
return bean;
}
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright 2008-2010 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 org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.Test;
import org.springframework.data.repository.support.IdAware;
import org.springframework.data.repository.support.IsNewAware;
/**
* Unit test for various implementations of {@link IsNewAware}.
*
* @author Oliver Gierke
*/
public class JpaAnnotationEntityInformationUnitTests {
@Test(expected = IllegalArgumentException.class)
public void rejectsNullAsDomainClass() throws Exception {
new JpaAnnotationEntityInformation(null);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNonEntityClasses() throws Exception {
new JpaAnnotationEntityInformation(NotAnnotatedEntity.class);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsEntityWithMissingIdAnnotation() throws Exception {
new JpaAnnotationEntityInformation(EntityWithOutIdAnnotation.class);
}
@Test
public void detectsFieldAnnotatedIdCorrectly() throws Exception {
JpaAnnotationEntityInformation info =
new JpaAnnotationEntityInformation(FieldAnnotatedEntity.class);
assertNewAndNoId(info, new FieldAnnotatedEntity(null));
assertNotNewAndId(info, new FieldAnnotatedEntity(1L), 1L);
}
@Test
public void detectsEmbeddedIdFieldAnnotatedIdCorrectly() throws Exception {
JpaAnnotationEntityInformation info =
new JpaAnnotationEntityInformation(
EmbeddedIdFieldAnnotatedEntity.class);
assertNewAndNoId(info, new EmbeddedIdFieldAnnotatedEntity(null));
assertNotNewAndId(info, new EmbeddedIdFieldAnnotatedEntity(1L), 1L);
}
@Test
public void detectsMethodAnnotatedIdCorrectly() throws Exception {
JpaAnnotationEntityInformation info =
new JpaAnnotationEntityInformation(MethodAnnotatedEntity.class);
assertNewAndNoId(info, new MethodAnnotatedEntity());
MethodAnnotatedEntity entity = new MethodAnnotatedEntity();
entity.id = 1L;
assertNotNewAndId(info, entity, 1L);
}
@Test
public void detectsEmbeddedIdMethodAnnotatedIdCorrectly() throws Exception {
JpaAnnotationEntityInformation strategy =
new JpaAnnotationEntityInformation(
EmbeddedIdMethodAnnotatedEntity.class);
assertNewAndNoId(strategy, new EmbeddedIdMethodAnnotatedEntity());
EmbeddedIdMethodAnnotatedEntity entity =
new EmbeddedIdMethodAnnotatedEntity();
entity.id = 1L;
assertNotNewAndId(strategy, entity, 1L);
}
private <T extends IdAware & IsNewAware> void assertNewAndNoId(T info,
Object entity) {
assertThat(info.isNew(entity), is(true));
assertThat(info.getId(entity), is(nullValue()));
}
private <T extends IdAware & IsNewAware> void assertNotNewAndId(T info,
Object entity, Object id) {
assertThat(info.isNew(entity), is(false));
assertThat(info.getId(entity), is(id));
}
@Entity
static class FieldAnnotatedEntity {
@Id
Long id;
public FieldAnnotatedEntity(Long id) {
this.id = id;
}
}
@Entity
static class EmbeddedIdFieldAnnotatedEntity {
@EmbeddedId
Long id;
public EmbeddedIdFieldAnnotatedEntity(Long id) {
this.id = id;
}
}
@Entity
static class MethodAnnotatedEntity {
private Long id;
@Id
public Long getId() {
return id;
}
}
@Entity
static class EmbeddedIdMethodAnnotatedEntity {
private Long id;
@EmbeddedId
public Long getId() {
return id;
}
}
static class NotAnnotatedEntity {
@Id
public Long id;
}
@Entity
static class EntityWithOutIdAnnotation {
}
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright 2008-2010 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 org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
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.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* Unit test for {@code GenericDaoFactoryBean}.
* <p>
* TODO: Check if test methods double the ones in
* {@link JpaRepositoryFactoryUnitTests}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class JpaRepositoryFactoryBeanUnitTests {
JpaRepositoryFactoryBean<SimpleSampleRepository> factory;
@Mock
EntityManager entityManager;
@Mock
ListableBeanFactory beanFactory;
@Mock
PersistenceExceptionTranslator translator;
@Before
public void setUp() {
Map<String, PersistenceExceptionTranslator> beans =
new HashMap<String, PersistenceExceptionTranslator>();
beans.put("foo", translator);
when(
beanFactory.getBeansOfType(
eq(PersistenceExceptionTranslator.class), anyBoolean(),
anyBoolean())).thenReturn(beans);
// Setup standard factory configuration
factory =
JpaRepositoryFactoryBean.create(
SimpleSampleRepository.class, entityManager);
factory.setEntityManager(entityManager);
}
/**
* Assert that the instance created for the standard configuration is a
* valid {@code UserDao}.
*
* @throws Exception
*/
@Test
public void setsUpBasicInstanceCorrectly() throws Exception {
factory.setBeanFactory(beanFactory);
factory.afterPropertiesSet();
assertNotNull(factory.getObject());
}
@Test(expected = IllegalArgumentException.class)
public void requiresListableBeanFactory() throws Exception {
factory.setBeanFactory(mock(BeanFactory.class));
}
/**
* Assert that the factory rejects calls to
* {@code GenericDaoFactoryBean#setDaoInterface(Class)} with {@code null} or
* any other parameter instance not implementing {@code GenericDao}.
*/
@Test(expected = IllegalArgumentException.class)
public void preventsNullDaoInterface() {
factory.setRepositoryInterface(null);
}
/**
* Assert that the factory detects unset DAO class and interface in
* {@code GenericDaoFactoryBean#afterPropertiesSet()}.
*/
@Test(expected = IllegalArgumentException.class)
public void preventsUnsetDaoInterface() throws Exception {
factory = new JpaRepositoryFactoryBean<SimpleSampleRepository>();
factory.afterPropertiesSet();
}
/**
* Asserts that the factory recognized configured DAO classes that contain
* custom method but no custom implementation could be found. Furthremore
* the exception has to contain the name of the DAO interface as for a large
* DAO configuration it's hard to find out where this error occured.
*
* @throws Exception
*/
@Test
public void capturesMissingCustomImplementationAndProvidesInterfacename()
throws Exception {
JpaRepositoryFactoryBean<SampleRepository> factory =
JpaRepositoryFactoryBean.create(SampleRepository.class,
entityManager);
try {
factory.afterPropertiesSet();
fail("Expected IllegalArgumentException!");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage()
.contains(SampleRepository.class.getName()));
}
}
private interface SimpleSampleRepository extends
JpaRepository<User, Integer> {
}
/**
* Sample interface to contain a custom method.
*
* @author Oliver Gierke
*/
private interface SampleCustomDao {
void someSampleMethod();
}
private interface SampleRepository extends
JpaRepository<User, Integer>, SampleCustomDao {
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright 2008-2010 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 junit.framework.Assert.*;
import java.io.IOException;
import javax.persistence.EntityManager;
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.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.custom.CustomGenericJpaRepositoryFactory;
import org.springframework.data.jpa.repository.custom.UserCustomExtendedRepository;
import org.springframework.transaction.annotation.Transactional;
/**
* Unit test for {@code GenericDaoFactoryBean}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class JpaRepositoryFactoryUnitTests {
JpaRepositoryFactory factory;
@Mock
EntityManager entityManager;
@Before
public void setUp() {
// Setup standard factory configuration
factory = new JpaRepositoryFactory(entityManager);
}
/**
* Assert that the instance created for the standard configuration is a
* valid {@code UserDao}.
*
* @throws Exception
*/
@Test
public void setsUpBasicInstanceCorrectly() throws Exception {
assertNotNull(factory.getRepository(SimpleSampleDao.class));
}
@Test
public void allowsCallingOfObjectMethods() {
SimpleSampleDao userDao = factory.getRepository(SimpleSampleDao.class);
userDao.hashCode();
userDao.toString();
userDao.equals(userDao);
}
/**
* Asserts that the factory recognized configured DAO classes that contain
* custom method but no custom implementation could be found. Furthremore
* the exception has to contain the name of the DAO interface as for a large
* DAO configuration it's hard to find out where this error occured.
*
* @throws Exception
*/
@Test
public void capturesMissingCustomImplementationAndProvidesInterfacename()
throws Exception {
try {
factory.getRepository(SampleDao.class);
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains(SampleDao.class.getName()));
}
}
@Test(expected = IllegalArgumentException.class)
public void handlesRuntimeExceptionsCorrectly() {
SampleDao dao =
factory.getRepository(SampleDao.class,
new SampleCustomDaoImpl());
dao.throwingRuntimeException();
}
@Test(expected = IOException.class)
public void handlesCheckedExceptionsCorrectly() throws Exception {
SampleDao dao =
factory.getRepository(SampleDao.class,
new SampleCustomDaoImpl());
dao.throwingCheckedException();
}
@Test(expected = UnsupportedOperationException.class)
public void createsProxyWithCustomBaseClass() throws Exception {
JpaRepositoryFactory factory =
new CustomGenericJpaRepositoryFactory(entityManager);
UserCustomExtendedRepository dao =
factory.getRepository(UserCustomExtendedRepository.class);
dao.customMethod(1);
}
private interface SimpleSampleDao extends
JpaRepository<User, Integer> {
@Transactional
User readByPrimaryKey(Integer primaryKey);
}
/**
* Sample interface to contain a custom method.
*
* @author Oliver Gierke
*/
public interface SampleCustomDao {
void throwingRuntimeException();
void throwingCheckedException() throws IOException;
}
/**
* Implementation of the custom DAO interface.
*
* @author Oliver Gierke
*/
private class SampleCustomDaoImpl implements SampleCustomDao {
public void throwingRuntimeException() {
throw new IllegalArgumentException("You lose!");
}
public void throwingCheckedException() throws IOException {
throw new IOException("You lose!");
}
}
private interface SampleDao extends JpaRepository<User, Integer>,
SampleCustomDao {
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2008-2010 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 org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.junit.Before;
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.repository.JpaRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration test for {@link GenericJpaDao}.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:infrastructure.xml" })
@Transactional
public class JpaRepositoryTests {
@PersistenceContext
EntityManager em;
JpaRepository<SampleEntity, SampleEntityPK> repository;
@Before
public void setUp() {
repository =
new JpaRepositoryFactory(em)
.getRepository(SampleEntityRepository.class);
}
@Test
public void testCrudOperationsForCompoundKeyEntity() throws Exception {
SampleEntity entity = new SampleEntity("foo", "bar");
repository.saveAndFlush(entity);
assertThat(repository.count(), is(1L));
assertThat(repository.findById(new SampleEntityPK("foo", "bar")),
is(entity));
repository.delete(Arrays.asList(entity));
repository.flush();
assertThat(repository.count(), is(0L));
}
private static interface SampleEntityRepository extends
JpaRepository<SampleEntity, SampleEntityPK> {
}
}

View File

@@ -0,0 +1,138 @@
package org.springframework.data.jpa.repository.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
/**
* Integration test for transactional behaviour of DAO operations.
*
* @author Oliver Gierke
*/
@ContextConfiguration({ "classpath:config/namespace-autoconfig-context.xml",
"classpath:tx-manager.xml" })
public class TransactionalRepositoryTests extends
AbstractJUnit4SpringContextTests {
@Autowired
UserRepository repository;
@Autowired
DelegatingTransactionManager transactionManager;
@Before
public void setUp() {
transactionManager.resetCount();
}
@After
public void tearDown() {
repository.deleteAll();
}
@Test
public void simpleManipulatingOperation() throws Exception {
repository.saveAndFlush(new User("foo", "bar", "foo@bar.de"));
assertThat(transactionManager.getTransactionRequests(), is(1));
}
@Test
public void unannotatedFinder() throws Exception {
repository.findByEmailAddress("foo@bar.de");
assertThat(transactionManager.getTransactionRequests(), is(0));
}
@Test
public void invokeTransactionalFinder() throws Exception {
repository.findByHadesQuery("foo@bar.de");
assertThat(transactionManager.getTransactionRequests(), is(1));
}
@Test
public void invokeRedeclaredMethod() throws Exception {
repository.findById(1);
assertFalse(transactionManager.getDefinition().isReadOnly());
}
public static class DelegatingTransactionManager implements
PlatformTransactionManager {
private PlatformTransactionManager txManager;
private int transactionRequests;
private TransactionDefinition definition;
public DelegatingTransactionManager(PlatformTransactionManager txManager) {
this.txManager = txManager;
}
public void commit(TransactionStatus status)
throws TransactionException {
txManager.commit(status);
}
public TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException {
this.transactionRequests++;
this.definition = definition;
return txManager.getTransaction(definition);
}
public int getTransactionRequests() {
return transactionRequests;
}
public TransactionDefinition getDefinition() {
return definition;
}
public void resetCount() {
this.transactionRequests = 0;
this.definition = null;
}
public void rollback(TransactionStatus status)
throws TransactionException {
txManager.rollback(status);
}
}
}

View File

@@ -0,0 +1,4 @@
<html>
<head></head>
<body>Test cases for ORM DAO implementations.</body>
</html>

View File

@@ -0,0 +1,31 @@
package org.springframework.data.jpa.repository.util;
import static org.junit.Assert.*;
import static org.springframework.data.jpa.repository.utils.JpaClassUtils.*;
import javax.persistence.Entity;
import org.junit.Test;
/**
* @author Oliver Gierke
*/
public class JpaClassUtilsUnitTests {
@Test
public void usesSimpleClassNameIfNoEntityNameGiven() throws Exception {
assertEquals("User", getEntityName(User.class));
assertEquals("AnotherNamedUser", getEntityName(NamedUser.class));
}
static class User {
}
@Entity(name = "AnotherNamedUser")
static class NamedUser {
}
}