From ee257548fff73be0af30d71408c2ea6203ac86cf Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Mon, 7 Apr 2014 13:10:30 +0200 Subject: [PATCH] DATAJPA-509 - JpaMetamodelEntityInformation now considers entity name from JPA meta-model. JpaMetamodelEntityInformation prefers the entity name from the JPA meta-model over the one derived from the simple class name. Documented limitation of an entity name customized through XML mapping metadata will not be considered in the SpEL support for manually defined query methods. Original pull request: #76. --- src/docbkx/jpa.xml | 21 ++++++---- .../JpaMetamodelEntityInformation.java | 24 +++++++---- .../data/jpa/domain/sample/Role.java | 12 ++++-- .../RoleRepositoryIntegrationTests.java | 42 +++++++++++++++++-- .../config/QueryLookupStrategyTests.java | 12 +++--- .../jpa/repository/sample/RoleRepository.java | 6 +++ ...odelEntityInformationIntegrationTests.java | 16 ++++++- src/test/resources/META-INF/orm.xml | 2 +- .../config/lookup-strategies-context.xml | 2 +- 9 files changed, 106 insertions(+), 31 deletions(-) diff --git a/src/docbkx/jpa.xml b/src/docbkx/jpa.xml index 03a21ba05..2dc8695fc 100644 --- a/src/docbkx/jpa.xml +++ b/src/docbkx/jpa.xml @@ -321,7 +321,7 @@ class ApplicationConfig { … where x.lastname = ?1 or x.firstname = ?2 - + Is,Equals @@ -346,7 +346,7 @@ class ApplicationConfig { … where x.age < ?1 - + LessThanEqual @@ -362,7 +362,7 @@ class ApplicationConfig { … where x.age > ?1 - + GreaterThanEqual @@ -496,15 +496,15 @@ class ApplicationConfig { … where x.active = false - + IgnoreCase findByFirstnameIgnoreCase - … where UPPER(x.firstame) = UPPER(?1) + … where UPPER(x.firstame) = + UPPER(?1) - @@ -748,6 +748,13 @@ public class User { the query string of a @Query annotation one can use the #{#entityName} Variable. + + The entityName can be customized via the + @Entity annotation. Customizations via + orm.xml are not supported for the SpEL + expressions. + + Using SpEL expressions in Repository query methods - entityName @@ -1067,7 +1074,7 @@ class UserManagementImpl implements UserManagement { none already running). The transaction configuration at the repositories will be neglected then as the outer transaction configuration determines the actual one used. Note that you will have to activate - <tx:annotation-driven /> or use + <tx:annotation-driven /> or use @EnableTransactionManagement explicitly to get annotation based configuration at facades working. The example above assumes you are using component scanning. diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java index c43d2c5e7..f8a6995d4 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 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. @@ -24,6 +24,7 @@ import java.util.List; import java.util.Set; import javax.persistence.IdClass; +import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.IdentifiableType; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; @@ -51,6 +52,7 @@ public class JpaMetamodelEntityInformation extends J private final IdMetadata idMetadata; private final SingularAttribute versionAttribute; private final Metamodel metamodel; + private final String entityName; /** * Creates a new {@link JpaMetamodelEntityInformation} for the given domain class and {@link Metamodel}. @@ -66,11 +68,12 @@ public class JpaMetamodelEntityInformation extends J this.metamodel = metamodel; ManagedType type = metamodel.managedType(domainClass); - if (type == null) { throw new IllegalArgumentException("The given domain class can not be found in the given Metamodel!"); } + this.entityName = type instanceof EntityType ? ((EntityType) type).getName() : null; + if (!(type instanceof IdentifiableType)) { throw new IllegalArgumentException("The given domain class does not contain an id attribute!"); } @@ -79,6 +82,15 @@ public class JpaMetamodelEntityInformation extends J this.versionAttribute = findVersionAttribute(type); } + /* + * (non-Javadoc) + * @see org.springframework.data.jpa.repository.support.JpaEntityInformationSupport#getEntityName() + */ + @Override + public String getEntityName() { + return entityName != null ? entityName : super.getEntityName(); + } + /** * Returns the version attribute of the given {@link ManagedType} or {@literal null} if none available. * @@ -129,9 +141,7 @@ public class JpaMetamodelEntityInformation extends J /* * (non-Javadoc) - * - * @see - * org.springframework.data.repository.support.EntityInformation#getIdType() + * @see org.springframework.data.repository.core.EntityInformation#getIdType() */ @SuppressWarnings("unchecked") public Class getIdType() { @@ -140,9 +150,7 @@ public class JpaMetamodelEntityInformation extends J /* * (non-Javadoc) - * - * @see org.springframework.data.jpa.repository.support.JpaEntityMetadata# - * getIdAttribute() + * @see org.springframework.data.jpa.repository.support.JpaEntityInformation#getIdAttribute() */ public SingularAttribute getIdAttribute() { return idMetadata.getSimpleIdAttribute(); diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/Role.java b/src/test/java/org/springframework/data/jpa/domain/sample/Role.java index 1a9da0c6b..604291031 100644 --- a/src/test/java/org/springframework/data/jpa/domain/sample/Role.java +++ b/src/test/java/org/springframework/data/jpa/domain/sample/Role.java @@ -36,9 +36,7 @@ public class Role { /** * Creates a new instance of {@code Role}. */ - public Role() { - - } + public Role() {} /** * Creates a new preconfigured {@code Role}. @@ -46,7 +44,6 @@ public class Role { * @param name */ public Role(final String name) { - this.name = name; } @@ -60,6 +57,13 @@ public class Role { return id; } + /** + * @return the name + */ + public String getName() { + return name; + } + /* * (non-Javadoc) * diff --git a/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java index 8970d9a1d..e9db15183 100644 --- a/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * Copyright 2011-2014 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. @@ -32,14 +32,14 @@ import org.springframework.transaction.annotation.Transactional; * Integration tests for {@link RoleRepository}. * * @author Oliver Gierke + * @author Thomas Darimont */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:application-context.xml" }) @Transactional public class RoleRepositoryIntegrationTests { - @Autowired - RoleRepository repository; + @Autowired RoleRepository repository; @Test public void createsRole() throws Exception { @@ -62,4 +62,40 @@ public class RoleRepositoryIntegrationTests { assertThat(repository.findOne(result.getId()), is(reference)); } + + /** + * @see DATAJPA-509 + */ + @Test + public void shouldUseExplicitlyConfiguredEntityNameInOrmXmlInCountQueries() { + + Role reference = new Role("ADMIN"); + repository.save(reference); + + assertThat(repository.count(), is(1L)); + } + + /** + * @see DATAJPA-509 + */ + @Test + public void shouldUseExplicitlyConfiguredEntityNameInOrmXmlInExistsQueries() { + + Role reference = new Role("ADMIN"); + reference = repository.save(reference); + + assertThat(repository.exists(reference.getId()), is(true)); + } + + /** + * @see DATAJPA-509 + */ + @Test + public void shouldUseExplicitlyConfiguredEntityNameInDerivedCountQueries() { + + Role reference = new Role("ADMIN"); + reference = repository.save(reference); + + assertThat(repository.countByName(reference.getName()), is(1L)); + } } diff --git a/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java b/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java index 737d03a0b..c320d4f63 100644 --- a/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 the original author or authors. + * Copyright 2008-2014 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. @@ -32,22 +32,22 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * Integration test for XML configuration of {@link QueryLookupStrategy.Key}s. * * @author Oliver Gierke + * @author Thomas Darimont */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:config/lookup-strategies-context.xml") public class QueryLookupStrategyTests { - @Autowired - ApplicationContext context; + @Autowired ApplicationContext context; /** - * Assert that {@link QueryLookupStrategy#USE_DECLARED_QUERY} is being set on the factory if configured. + * Assert that {@link Key#CREATE_IF_NOT_FOUND} is being set on the factory if configured. */ @Test - public void assertUseDeclaredQuery() { + public void shouldUseExplicitlyConfiguredQueryLookUpStrategy() { JpaRepositoryFactoryBean factory = context.getBean("&roleRepository", JpaRepositoryFactoryBean.class); - assertEquals(Key.USE_DECLARED_QUERY, getField(factory, "queryLookupStrategyKey")); + assertEquals(Key.CREATE_IF_NOT_FOUND, getField(factory, "queryLookupStrategyKey")); } } diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java index 81cfa1337..fe03bb219 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java @@ -25,6 +25,7 @@ import org.springframework.data.repository.CrudRepository; * Typing interface for {@code Role}. * * @author Oliver Gierke + * @author Thomas Darimont */ public interface RoleRepository extends CrudRepository { @@ -41,4 +42,9 @@ public interface RoleRepository extends CrudRepository { */ @Lock(LockModeType.READ) Role findOne(Integer id); + + /** + * @see DATAJPA-509 + */ + long countByName(String name); } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java index 3eb89536c..a5d0fd2bb 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 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. @@ -36,6 +36,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.data.jpa.domain.AbstractPersistable; +import org.springframework.data.jpa.domain.sample.Role; import org.springframework.data.jpa.domain.sample.SampleWithIdClass; import org.springframework.data.jpa.domain.sample.SampleWithIdClassPK; import org.springframework.data.jpa.domain.sample.SampleWithPrimitiveId; @@ -49,6 +50,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * Integration tests for {@link JpaMetamodelEntityInformation}. * * @author Oliver Gierke + * @author Thomas Darimont */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({ "classpath:infrastructure.xml" }) @@ -155,6 +157,18 @@ public class JpaMetamodelEntityInformationIntegrationTests { assertThat(information.isNew(sample), is(false)); } + /** + * @see DATAJPA-509 + */ + @Test + public void jpaMetamodelEntityInformationShouldRespectExplicitlyConfiguredEntityNameFromOrmXml() { + + JpaEntityInformation info = new JpaMetamodelEntityInformation(Role.class, + em.getMetamodel()); + + assertThat(info.getEntityName(), is("ROLE")); + } + protected String getMetadadataPersitenceUnitName() { return "metadata"; } diff --git a/src/test/resources/META-INF/orm.xml b/src/test/resources/META-INF/orm.xml index 8bb0b959c..89cbea582 100644 --- a/src/test/resources/META-INF/orm.xml +++ b/src/test/resources/META-INF/orm.xml @@ -13,7 +13,7 @@ SELECT u FROM User u WHERE u.lastname = ?1 - + diff --git a/src/test/resources/config/lookup-strategies-context.xml b/src/test/resources/config/lookup-strategies-context.xml index 541a85a80..c484a76fc 100644 --- a/src/test/resources/config/lookup-strategies-context.xml +++ b/src/test/resources/config/lookup-strategies-context.xml @@ -9,7 +9,7 @@ - +