diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java b/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java index 26a308bed..c3267d1a3 100644 --- a/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java +++ b/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 the original author or authors. + * Copyright 2008-2015 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. @@ -30,6 +30,7 @@ import org.springframework.data.jpa.domain.AbstractAuditable; * necessary. Furthermore no auditing information has to be declared explicitly. * * @author Oliver Gierke + * @author Thomas Darimont */ @Entity @NamedQuery(name = "AuditableUser.findByFirstname", query = "SELECT u FROM AuditableUser u WHERE u.firstname = ?1") @@ -42,13 +43,16 @@ public class AuditableUser extends AbstractAuditable { @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }) private Set roles = new HashSet(); public AuditableUser() { - this(null); } public AuditableUser(Integer id) { + this(id, null); + } - this.setId(id); + public AuditableUser(Integer id, String firstname) { + setId(id); + this.firstname = firstname; } /** diff --git a/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java b/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java index 37c57d92f..71a104050 100644 --- a/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2015 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. @@ -19,18 +19,28 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import java.util.Date; +import java.util.List; import java.util.concurrent.TimeUnit; +import javax.persistence.EntityManager; + +import org.joda.time.DateTime; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.domain.AuditorAware; import org.springframework.data.jpa.domain.sample.AuditableUser; import org.springframework.data.jpa.repository.sample.AuditableUserRepository; +import org.springframework.data.jpa.repository.sample.SampleEvaluationContextExtension; +import org.springframework.data.jpa.repository.sample.SampleEvaluationContextExtension.SampleSecurityContextHolder; +import org.springframework.data.jpa.util.FixedDate; +import org.springframework.data.repository.query.spi.EvaluationContextExtension; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; @@ -48,10 +58,17 @@ public abstract class AbstractAuditingViaJavaConfigRepositoriesTests { @Autowired AuditorAware auditorAware; AuditableUser auditor; + @Autowired EntityManager em; + @Configuration @Import(InfrastructureConfig.class) @EnableJpaRepositories(basePackageClasses = AuditableUserRepository.class) - static class TestConfig {} + static class TestConfig { + @Bean + EvaluationContextExtension sampleEvaluationContextExtension() { + return new SampleEvaluationContextExtension(); + } + } @Before public void setup() { @@ -84,4 +101,35 @@ public abstract class AbstractAuditingViaJavaConfigRepositoriesTests { assertThat(createdBy, is(notNullValue())); assertThat(createdBy.getFirstname(), is(this.auditor.getFirstname())); } + + /** + * @see DATAJPA-382 + */ + @Test + public void shouldAllowUseOfDynamicSpelParametersInUpdateQueries() { + + AuditableUser oliver = auditableUserRepository.save(new AuditableUser(null, "oliver")); + AuditableUser christoph = auditableUserRepository.save(new AuditableUser(null, "christoph")); + AuditableUser thomas = auditableUserRepository.save(new AuditableUser(null, "thomas")); + + em.detach(oliver); + em.detach(christoph); + em.detach(thomas); + em.detach(auditor); + + FixedDate.INSTANCE.setDate(new Date()); + + SampleSecurityContextHolder.getCurrent().setPrincipal(thomas); + auditableUserRepository.updateAllNamesToUpperCase(); + + DateTime now = new DateTime(FixedDate.INSTANCE.getDate()); + List users = auditableUserRepository.findAll(); + + for (AuditableUser user : users) { + + assertThat(user.getFirstname(), is(user.getFirstname().toUpperCase())); + assertThat(user.getLastModifiedBy(), is(thomas)); + assertThat(user.getLastModifiedDate(), is(now)); + } + } } diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java index 7a7b91df3..1ffb0c72c 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 the original author or authors. + * Copyright 2008-2015 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. @@ -19,11 +19,14 @@ import java.util.List; import org.springframework.data.jpa.domain.sample.AuditableUser; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; /** * Repository interface for {@code AuditableUser}. * * @author Oliver Gierke + * @author Thomas Darimont */ public interface AuditableUserRepository extends JpaRepository { @@ -33,5 +36,9 @@ public interface AuditableUserRepository extends JpaRepository findByFirstname(final String firstname); + List findByFirstname(final String firstname); + + @Modifying + @Query("update AuditableUser a set a.firstname = upper(a.firstname), a.lastModifiedBy = :#{#security.principal}, a.lastModifiedDate = :#{T(org.springframework.data.jpa.util.FixedDate).INSTANCE.getDate()}") + void updateAllNamesToUpperCase(); } diff --git a/src/test/java/org/springframework/data/jpa/util/FixedDate.java b/src/test/java/org/springframework/data/jpa/util/FixedDate.java new file mode 100644 index 000000000..996697ec8 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/util/FixedDate.java @@ -0,0 +1,38 @@ +/* + * Copyright 2015 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.util; + +import java.util.Date; + +/** + * Holds a fixed {@link Date} value to use in components that have no direct connection. + * + * @author Thomas Darimont + */ +public enum FixedDate { + + INSTANCE; + + private Date fixedDate; + + public void setDate(Date date) { + this.fixedDate = date; + } + + public Date getDate() { + return fixedDate; + } +}