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.
This commit is contained in:
Thomas Darimont
2014-04-07 13:10:30 +02:00
committed by Oliver Gierke
parent 4dd570f670
commit ff0170967d
9 changed files with 106 additions and 31 deletions

View File

@@ -321,7 +321,7 @@ class ApplicationConfig {
<entry><code>… where x.lastname = ?1 or x.firstname =
?2</code></entry>
</row>
<row>
<entry><code>Is,Equals</code></entry>
@@ -346,7 +346,7 @@ class ApplicationConfig {
<entry><code>… where x.age &lt; ?1</code></entry>
</row>
<row>
<entry><code>LessThanEqual</code></entry>
@@ -362,7 +362,7 @@ class ApplicationConfig {
<entry><code>… where x.age &gt; ?1</code></entry>
</row>
<row>
<entry><code>GreaterThanEqual</code></entry>
@@ -496,15 +496,15 @@ class ApplicationConfig {
<entry><code>… where x.active = false</code></entry>
</row>
<row>
<entry><code>IgnoreCase</code></entry>
<entry><code>findByFirstnameIgnoreCase</code></entry>
<entry><code>… where UPPER(x.firstame) = UPPER(?1)</code></entry>
<entry><code>… where UPPER(x.firstame) =
UPPER(?1)</code></entry>
</row>
</tbody>
</tgroup>
</table><note>
@@ -748,6 +748,13 @@ public class User {
the query string of a <code>@Query</code> annotation one can use the
<code>#{#entityName}</code> Variable.</para>
<note>
<para>The <code>entityName</code> can be customized via the
<code>@Entity</code> annotation. Customizations via
<literal>orm.xml</literal> are not supported for the SpEL
expressions.</para>
</note>
<example>
<title>Using SpEL expressions in Repository query methods -
entityName</title>
@@ -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
<code>&lt;tx:annotation-driven /&gt;</code> or use
<code>&lt;tx:annotation-driven /&gt;</code> or use
<interfacename>@EnableTransactionManagement</interfacename> explicitly
to get annotation based configuration at facades working. The example
above assumes you are using component scanning.</para>

View File

@@ -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.
@@ -23,6 +23,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;
@@ -48,6 +49,7 @@ public class JpaMetamodelEntityInformation<T, ID extends Serializable> extends J
private final IdMetadata<T> idMetadata;
private final SingularAttribute<? super T, ?> versionAttribute;
private final Metamodel metamodel;
private final String entityName;
/**
* Creates a new {@link JpaMetamodelEntityInformation} for the given domain class and {@link Metamodel}.
@@ -63,11 +65,12 @@ public class JpaMetamodelEntityInformation<T, ID extends Serializable> extends J
this.metamodel = metamodel;
ManagedType<T> 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!");
}
@@ -76,6 +79,15 @@ public class JpaMetamodelEntityInformation<T, ID extends Serializable> 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.
*
@@ -126,9 +138,7 @@ public class JpaMetamodelEntityInformation<T, ID extends Serializable> extends J
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.repository.support.EntityInformation#getIdType()
* @see org.springframework.data.repository.core.EntityInformation#getIdType()
*/
@SuppressWarnings("unchecked")
public Class<ID> getIdType() {
@@ -137,9 +147,7 @@ public class JpaMetamodelEntityInformation<T, ID extends Serializable> extends J
/*
* (non-Javadoc)
*
* @see org.springframework.data.jpa.repository.support.JpaEntityMetadata#
* getIdAttribute()
* @see org.springframework.data.jpa.repository.support.JpaEntityInformation#getIdAttribute()
*/
public SingularAttribute<? super T, ?> getIdAttribute() {
return idMetadata.getSimpleIdAttribute();

View File

@@ -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)
*

View File

@@ -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));
}
}

View File

@@ -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"));
}
}

View File

@@ -27,6 +27,7 @@ import org.springframework.data.repository.CrudRepository;
* Typing interface for {@code Role}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public interface RoleRepository extends CrudRepository<Role, Integer> {
@@ -45,4 +46,9 @@ public interface RoleRepository extends CrudRepository<Role, Integer> {
@Lock(LockModeType.READ)
@QueryHints(@QueryHint(name = "foo", value = "bar"))
Role findOne(Integer id);
/**
* @see DATAJPA-509
*/
long countByName(String name);
}

View File

@@ -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<Role, Integer> info = new JpaMetamodelEntityInformation<Role, Integer>(Role.class,
em.getMetamodel());
assertThat(info.getEntityName(), is("ROLE"));
}
protected String getMetadadataPersitenceUnitName() {
return "metadata";
}

View File

@@ -13,7 +13,7 @@
<query>SELECT u FROM User u WHERE u.lastname = ?1</query>
</named-query>
<entity class="org.springframework.data.jpa.domain.sample.Role" access="FIELD">
<entity class="org.springframework.data.jpa.domain.sample.Role" access="FIELD" name="ROLE">
<attributes>
<id name="id">
<generated-value strategy="AUTO" />

View File

@@ -9,7 +9,7 @@
<import resource="../infrastructure.xml" />
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" query-lookup-strategy="use-declared-query">
<jpa:repositories base-package="org.springframework.data.jpa.repository.sample" query-lookup-strategy="create-if-not-found">
<repository:include-filter type="assignable" expression="org.springframework.data.jpa.repository.sample.RoleRepository" />
</jpa:repositories>