diff --git a/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java new file mode 100644 index 000000000..3acc3329a --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java @@ -0,0 +1,91 @@ +/* + * Copyright 2013 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 org.springframework.data.jpa.repository.support.JpaEntityMetadata; +import org.springframework.data.repository.core.EntityMetadata; +import org.springframework.expression.Expression; +import org.springframework.expression.ParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.Assert; + +/** + * Extension of {@link StringQuery} that evaluates the given query string as a SpEL template-expression. + *

+ * Currently the following template variables are available: + *

    + *
  1. {@code #entityName} - the simple class name of the given entity
  2. + *
      + * + * @author Thomas Darimont + * @author Oliver Gierke + */ +class ExpressionBasedStringQuery extends StringQuery { + + private static final String ENTITY_NAME = "entityName"; + private final JpaEntityMetadata metadata; + + private String parsedQuery; + + /** + * Creates a new {@link ExpressionBasedStringQuery} for the given query and {@link EntityMetadata}. + * + * @param query must not be {@literal null} or empty. + * @param metadata must not be {@literal null}. + */ + public ExpressionBasedStringQuery(String query, JpaEntityMetadata metadata) { + + super(query); + Assert.notNull(metadata, "JpaEntityMetadata must not be null!"); + this.metadata = metadata; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.jpa.repository.query.StringQuery#getQuery() + */ + @Override + public String getQuery() { + + if (parsedQuery == null) { + String rawQuery = super.getQuery(); + this.parsedQuery = renderQueryIfExpressionOrReturnQuery(rawQuery); + } + + return this.parsedQuery; + } + + private String renderQueryIfExpressionOrReturnQuery(String query) { + + if (!containsExpression(query)) { + return query; + } + + StandardEvaluationContext evalContext = new StandardEvaluationContext(); + evalContext.setVariable(ENTITY_NAME, metadata.getEntityName()); + + SpelExpressionParser parser = new SpelExpressionParser(); + Expression expr = parser.parseExpression(query, ParserContext.TEMPLATE_EXPRESSION); + + Object result = expr.getValue(evalContext, String.class); + return result == null ? query : String.valueOf(result); + } + + private static boolean containsExpression(String query) { + return query.contains("#{#" + ENTITY_NAME + "}"); + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index 1eaabf9d3..08e9619ce 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 the original author or authors. + * Copyright 2008-2013 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,8 @@ import org.springframework.data.jpa.repository.Lock; 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.jpa.repository.support.DefaultJpaEntityMetadata; +import org.springframework.data.jpa.repository.support.JpaEntityMetadata; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; @@ -91,6 +93,16 @@ public class JpaQueryMethod extends QueryMethod { } } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.query.QueryMethod#getEntityInformation() + */ + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public JpaEntityMetadata getEntityInformation() { + return new DefaultJpaEntityMetadata(getDomainClass()); + } + /** * Returns whether the finder is a modifying one. * diff --git a/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java index 6b57a3159..7093eaea9 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2012 the original author or authors. + * Copyright 2008-2013 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,6 +32,7 @@ import org.springframework.data.repository.query.RepositoryQuery; * {@link Query} from it. * * @author Oliver Gierke + * @author Thomas Darimont */ final class SimpleJpaQuery extends AbstractJpaQuery { @@ -50,7 +51,7 @@ final class SimpleJpaQuery extends AbstractJpaQuery { super(method, em); this.method = method; - this.query = new StringQuery(queryString); + this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation()); Parameters parameters = method.getParameters(); boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter(); diff --git a/src/main/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadata.java b/src/main/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadata.java new file mode 100644 index 000000000..8e457cd7c --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadata.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013 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.Entity; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Default implementation for {@link JpaEntityMetadata}. + * + * @author Oliver Gierke + */ +public class DefaultJpaEntityMetadata implements JpaEntityMetadata { + + private final Class domainType; + + /** + * Creates a new {@link DefaultJpaEntityMetadata} for the given domain type. + * + * @param domainType must not be {@literal null}. + */ + public DefaultJpaEntityMetadata(Class domainType) { + + Assert.notNull(domainType, "Domain type must not be null!"); + this.domainType = domainType; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.EntityMetadata#getJavaType() + */ + @Override + public Class getJavaType() { + return domainType; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.jpa.repository.support.JpaEntityMetadata#getEntityName() + */ + public String getEntityName() { + + Entity entity = domainType.getAnnotation(Entity.class); + boolean hasName = null != entity && StringUtils.hasText(entity.name()); + + return hasName ? entity.name() : domainType.getSimpleName(); + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java index be13dc1fa..b221f8875 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java @@ -27,7 +27,8 @@ import org.springframework.data.repository.core.EntityInformation; * @author Oliver Gierke * @author Thomas Darimont */ -public interface JpaEntityInformation extends EntityInformation { +public interface JpaEntityInformation extends EntityInformation, + JpaEntityMetadata { /** * Returns the id attribute of the entity. @@ -59,11 +60,4 @@ public interface JpaEntityInformation extends Entity * @return */ Object getCompositeIdAttributeValue(Serializable id, String idAttribute); - - /** - * Returns the JPA entity name. - * - * @return - */ - String getEntityName(); } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java index 4eb9542a1..b62db08f8 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java @@ -17,14 +17,12 @@ package org.springframework.data.jpa.repository.support; import java.io.Serializable; -import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.metamodel.Metamodel; import org.springframework.data.domain.Persistable; import org.springframework.data.repository.core.support.AbstractEntityInformation; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; /** * Base class for {@link JpaEntityInformation} implementations to share common method implementations. @@ -34,14 +32,16 @@ import org.springframework.util.StringUtils; public abstract class JpaEntityInformationSupport extends AbstractEntityInformation implements JpaEntityInformation { + private JpaEntityMetadata metadata; + /** * Creates a new {@link JpaEntityInformationSupport} with the given domain class. * * @param domainClass must not be {@literal null}. */ public JpaEntityInformationSupport(Class domainClass) { - super(domainClass); + this.metadata = new DefaultJpaEntityMetadata(domainClass); } /** @@ -68,17 +68,9 @@ public abstract class JpaEntityInformationSupport ex /* * (non-Javadoc) - * - * @see - * org.springframework.data.jpa.repository.support.JpaEntityInformation# - * getEntityName() + * @see org.springframework.data.jpa.repository.support.JpaEntityMetadata#getEntityName() */ public String getEntityName() { - - Class domainClass = getJavaType(); - Entity entity = domainClass.getAnnotation(Entity.class); - boolean hasName = null != entity && StringUtils.hasText(entity.name()); - - return hasName ? entity.name() : domainClass.getSimpleName(); + return metadata.getEntityName(); } } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityMetadata.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityMetadata.java new file mode 100644 index 000000000..c54f27c85 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityMetadata.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013 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 org.springframework.data.repository.core.EntityMetadata; + +/** + * JPA specific extension of {@link EntityMetadata}. + * + * @author Oliver Gierke + */ +public interface JpaEntityMetadata extends EntityMetadata { + + /** + * Returns the name of the entity. + * + * @return + */ + String getEntityName(); +} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java index 4269ccbb0..c7b1371c1 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * Copyright 2011-2013 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,37 +32,28 @@ public class JpaPersistableEntityInformation, ID exten /** * Creates a new {@link JpaPersistableEntityInformation} for the given domain class and {@link Metamodel}. * - * @param domainClass - * @param metamodel + * @param domainClass must not be {@literal null}. + * @param metamodel must not be {@literal null}. */ public JpaPersistableEntityInformation(Class domainClass, Metamodel metamodel) { - super(domainClass, metamodel); } /* * (non-Javadoc) - * - * @see - * org.springframework.data.repository.support.AbstractEntityInformation - * #isNew(java.lang.Object) + * @see org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation#isNew(java.lang.Object) */ @Override public boolean isNew(T entity) { - return entity.isNew(); } /* * (non-Javadoc) - * - * @see - * org.springframework.data.jpa.repository.support.JpaMetamodelEntityMetadata - * #getId(java.lang.Object) + * @see org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation#getId(java.lang.Object) */ @Override public ID getId(T entity) { - return entity.getId(); } } diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java b/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java new file mode 100644 index 000000000..07e407922 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java @@ -0,0 +1,36 @@ +/* + * Copyright 2013 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.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +/** + * @author Thomas Darimont + */ +@MappedSuperclass +public abstract class AbstractMappedType { + + public AbstractMappedType() {} + + public AbstractMappedType(String attribute1) { + this.attribute1 = attribute1; + } + + @Id @GeneratedValue Long id; + String attribute1; +} diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType1.java b/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType1.java new file mode 100644 index 000000000..6ee66ffb8 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType1.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 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; + +/** + * @author Thomas Darimont + */ +@Entity +public class ConcreteType1 extends AbstractMappedType { + + public ConcreteType1() {} + + public ConcreteType1(String attribute1) { + super(attribute1); + } +} diff --git a/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType2.java b/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType2.java new file mode 100644 index 000000000..abfd0b69d --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType2.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 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; + +/** + * @author Thomas Darimont + */ +@Entity +public class ConcreteType2 extends AbstractMappedType { + + public ConcreteType2() {} + + public ConcreteType2(String attribute1) { + super(attribute1); + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java new file mode 100644 index 000000000..463bac057 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2013 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 java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.data.jpa.domain.sample.ConcreteType1; +import org.springframework.data.jpa.domain.sample.ConcreteType2; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.data.jpa.repository.sample.ConcreteRepository1; +import org.springframework.data.jpa.repository.sample.ConcreteRepository2; +import org.springframework.data.jpa.repository.sample.MappedTypeRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +/** + * Integration tests for {@link MappedTypeRepository}. + * + * @author Thomas Darimont + */ +@Transactional +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class MappedTypeRepositoryIntegrationTests { + + @Configuration + @ImportResource("classpath:infrastructure.xml") + @EnableJpaRepositories + static class Config {} + + @Autowired ConcreteRepository1 concreteRepository1; + @Autowired ConcreteRepository2 concreteRepository2; + + /** + * @see DATAJPA-170 + */ + @Test + public void supportForExpressionBasedQueryMethods() { + + concreteRepository1.save(new ConcreteType1("foo")); + concreteRepository2.save(new ConcreteType2("foo")); + + List concretes1 = concreteRepository1.findAllByAttribute1("foo"); + List concretes2 = concreteRepository2.findAllByAttribute1("foo"); + + assertThat(concretes1.size(), is(1)); + assertThat(concretes2.size(), is(1)); + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java new file mode 100644 index 000000000..6b5fca1d4 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2013 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 org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.jpa.repository.support.JpaEntityMetadata; + +/** + * Unit tests for {@link ExpressionBasedStringQuery}. + * + * @author Thomas Darimont + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class ExpressionBasedStringQueryUnitTests { + + @Mock JpaEntityMetadata metadata; + + /** + * @see DATAJPA-170 + */ + @Test + public void shouldReturnQueryWithDomainTypeExpressionReplacedWithSimpleDomainTypeName() { + + when(metadata.getEntityName()).thenReturn("User"); + + String source = "select from #{#entityName} u where u.firstname like :firstname"; + StringQuery query = new ExpressionBasedStringQuery(source, metadata); + assertThat(query.getQuery(), is("select from User u where u.firstname like :firstname")); + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java index e4aaed99e..4ecca6180 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java @@ -42,6 +42,8 @@ import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.sample.User; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.sample.UserRepository; +import org.springframework.data.jpa.repository.support.DefaultJpaEntityMetadata; +import org.springframework.data.jpa.repository.support.JpaEntityMetadata; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.query.Parameters; @@ -67,24 +69,29 @@ public class SimpleJpaQueryUnitTests { public @Rule ExpectedException exception = ExpectedException.none(); @Before + @SuppressWarnings({ "rawtypes", "unchecked" }) public void setUp() throws SecurityException, NoSuchMethodException { when(em.createQuery(anyString())).thenReturn(query); when(em.createQuery(anyString(), eq(Long.class))).thenReturn(query); when(em.getEntityManagerFactory()).thenReturn(emf); when(emf.createEntityManager()).thenReturn(em); + when(metadata.getDomainType()).thenReturn((Class) User.class); + when(metadata.getReturnedDomainClass(Mockito.any(Method.class))).thenReturn((Class) User.class); Method setUp = UserRepository.class.getMethod("findByLastname", String.class); method = new JpaQueryMethod(setUp, metadata, extractor); } @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) public void prefersDeclaredCountQueryOverCreatingOne() throws Exception { method = mock(JpaQueryMethod.class); when(method.getCountQuery()).thenReturn("foo"); when(method.getParameters()).thenReturn( new Parameters(SimpleJpaQueryUnitTests.class.getMethod("prefersDeclaredCountQueryOverCreatingOne"))); + when(method.getEntityInformation()).thenReturn((JpaEntityMetadata) new DefaultJpaEntityMetadata(User.class)); when(em.createQuery("foo", Long.class)).thenReturn(query); SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u"); diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository1.java b/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository1.java new file mode 100644 index 000000000..fd27000bc --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository1.java @@ -0,0 +1,25 @@ +/* + * Copyright 2013 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.ConcreteType1; + +/** + * @author Thomas Darimont + */ +public interface ConcreteRepository1 extends MappedTypeRepository { + +} diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository2.java b/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository2.java new file mode 100644 index 000000000..41524d83b --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository2.java @@ -0,0 +1,25 @@ +/* + * Copyright 2013 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.ConcreteType2; + +/** + * @author Thomas Darimont + */ +public interface ConcreteRepository2 extends MappedTypeRepository { + +} diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java new file mode 100644 index 000000000..5a9ce4a0b --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 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.AbstractMappedType; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +/** + * @author Thomas Darimont + */ +public interface MappedTypeRepository extends JpaRepository { + + @Query("from #{#entityName} t where t.attribute1=?1") + List findAllByAttribute1(String attribute1); +} diff --git a/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadataUnitTest.java b/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadataUnitTest.java new file mode 100644 index 000000000..b20022182 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadataUnitTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013 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.Entity; + +import org.junit.Test; + +/** + * Unit tests for {@link DefaultJpaEntityMetadata}. + * + * @author Oliver Gierke + */ +public class DefaultJpaEntityMetadataUnitTest { + + @Test(expected = IllegalArgumentException.class) + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void rejectsNullDomainType() { + new DefaultJpaEntityMetadata(null); + } + + @Test + public void returnsConfiguredType() { + + DefaultJpaEntityMetadata metadata = new DefaultJpaEntityMetadata(Foo.class); + assertThat(metadata.getJavaType(), is(equalTo(Foo.class))); + } + + @Test + public void returnsSimpleClassNameAsEntityNameByDefault() { + + DefaultJpaEntityMetadata metadata = new DefaultJpaEntityMetadata(Foo.class); + assertThat(metadata.getEntityName(), is(Foo.class.getSimpleName())); + } + + @Test + public void returnsCustomizedEntityNameIfConfigured() { + + DefaultJpaEntityMetadata metadata = new DefaultJpaEntityMetadata(Bar.class); + assertThat(metadata.getEntityName(), is("Entity")); + } + + static class Foo {} + + @Entity(name = "Entity") + static class Bar {} +} diff --git a/src/test/resources/META-INF/persistence.xml b/src/test/resources/META-INF/persistence.xml index cfdbee980..3678b4002 100644 --- a/src/test/resources/META-INF/persistence.xml +++ b/src/test/resources/META-INF/persistence.xml @@ -15,6 +15,9 @@ org.springframework.data.jpa.domain.sample.SampleEntityPK org.springframework.data.jpa.domain.sample.SampleWithIdClass org.springframework.data.jpa.domain.sample.VersionedUser + org.springframework.data.jpa.domain.sample.AbstractMappedType + org.springframework.data.jpa.domain.sample.ConcreteType1 + org.springframework.data.jpa.domain.sample.ConcreteType2 true