Browse Source

DATACMNS-49 - Added infrastructure to read queries from a Properties file.

Added NamedQueries abstraction to hide a map of names to manually defined queries. Added PropertiesBasedNamedQueries to hold the named queries in a Properties instance. Extended resolveQuery(…) method in QueryLookupStrategy to take a NamedQuery instance to allow query creation callback use the named queries.

Added optional 'named-queries-location' attribute to the repositories namespace the bean definition parser loads the properties from to populate a PropertiesBasedNamedQueries instance and pipe it into the repository factory. Store implementations have to default the name to lookup in their RepositoryConfiguraion class (see CommonRepositoryConfigInformation.getNamedQueriesLocation()).
pull/4/head
Oliver Gierke 15 years ago
parent
commit
7b3e61e050
  1. 4
      spring-data-commons-core/src/main/java/org/springframework/data/repository/config/AbstractRepositoryConfigDefinitionParser.java
  2. 6
      spring-data-commons-core/src/main/java/org/springframework/data/repository/config/CommonRepositoryConfigInformation.java
  3. 99
      spring-data-commons-core/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionParser.java
  4. 8
      spring-data-commons-core/src/main/java/org/springframework/data/repository/config/ParentDelegatingRepositoryConfigInformation.java
  5. 41
      spring-data-commons-core/src/main/java/org/springframework/data/repository/core/NamedQueries.java
  6. 57
      spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/PropertiesBasedNamedQueries.java
  7. 22
      spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java
  8. 14
      spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java
  9. 4
      spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java
  10. 13
      spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryMethod.java
  11. 7
      spring-data-commons-core/src/main/resources/org/springframework/data/repository/config/spring-repository-1.0.xsd
  12. 10
      spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java

4
spring-data-commons-core/src/main/java/org/springframework/data/repository/config/AbstractRepositoryConfigDefinitionParser.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2008-2010 the original author or authors.
* Copyright 2008-2011 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.
@ -206,6 +206,8 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR @@ -206,6 +206,8 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
context.getInterfaceName());
builder.addPropertyValue("queryLookupStrategyKey",
context.getQueryLookupStrategyKey());
builder.addPropertyValue("namedQueries",
new NamedQueriesBeanDefinitionParser(context.getNamedQueriesLocation()).parse(context.getSource(), parser));
String transactionManagerRef = context.getTransactionManagerRef();

6
spring-data-commons-core/src/main/java/org/springframework/data/repository/config/CommonRepositoryConfigInformation.java

@ -77,4 +77,10 @@ public interface CommonRepositoryConfigInformation { @@ -77,4 +77,10 @@ public interface CommonRepositoryConfigInformation {
*/
Key getQueryLookupStrategyKey();
/**
* Returns the location of the properties file to contain named queries.
*
* @return
*/
String getNamedQueriesLocation();
}

99
spring-data-commons-core/src/main/java/org/springframework/data/repository/config/NamedQueriesBeanDefinitionParser.java

@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
/*
* Copyright 2011 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.repository.config;
import java.util.Properties;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* {@link BeanDefinitionParser} to create {@link BeanDefinition}s of {@link NamedQueries} instances looking up a
* {@link Properties} file fom the given location.
*
* @author Oliver Gierke
*/
public class NamedQueriesBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATTRIBUTE = "named-queries-location";
private final String defaultLocation;
/**
* Creates a new {@link NamedQueriesBeanDefinitionParser} using the given default location.
*
* @param defaultLocation must be non-empty
*/
public NamedQueriesBeanDefinitionParser(String defaultLocation) {
Assert.hasText(defaultLocation);
this.defaultLocation = defaultLocation;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
*/
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionBuilder properties = BeanDefinitionBuilder.rootBeanDefinition(PropertiesFactoryBean.class);
properties.addPropertyValue("locations", getDefaultedLocation(element));
if (isDefaultLocation(element)) {
properties.addPropertyValue("ignoreResourceNotFound", true);
}
AbstractBeanDefinition propertiesDefinition = properties.getBeanDefinition();
propertiesDefinition.setSource(parserContext.extractSource(element));
BeanDefinitionBuilder namedQueries = BeanDefinitionBuilder.rootBeanDefinition(PropertiesBasedNamedQueries.class);
namedQueries.addConstructorArgValue(propertiesDefinition);
AbstractBeanDefinition namedQueriesDefinition = namedQueries.getBeanDefinition();
namedQueriesDefinition.setSource(parserContext.extractSource(element));
return namedQueriesDefinition;
}
/**
* Returns whether we should use the default location.
*
* @param element
* @return
*/
private boolean isDefaultLocation(Element element) {
return !StringUtils.hasText(element.getAttribute(ATTRIBUTE));
}
/**
* Returns the location to look for {@link Properties} if configured or the default one if not.
*
* @param element
* @return
*/
private String getDefaultedLocation(Element element) {
String locations = element.getAttribute(ATTRIBUTE);
return StringUtils.hasText(locations) ? locations : defaultLocation;
}
}

8
spring-data-commons-core/src/main/java/org/springframework/data/repository/config/ParentDelegatingRepositoryConfigInformation.java

@ -189,4 +189,12 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm @@ -189,4 +189,12 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent.getQueryLookupStrategyKey();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.CommonRepositoryConfigInformation#getNamedQueriesLocation()
*/
public String getNamedQueriesLocation() {
return parent.getNamedQueriesLocation();
}
}

41
spring-data-commons-core/src/main/java/org/springframework/data/repository/core/NamedQueries.java

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
/*
* Copyright 2011 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.repository.core;
/**
* Abstraction of a map of {@link NamedQueries} that can be looked up by their names.
*
* @author Oliver Gierke
*/
public interface NamedQueries {
/**
* Returns whether the map contains a named query for the given name. If this method returns {@literal true} you can
* expect {@link #getQuery(String)} to return a non-{@literal null} query for the very same name.
*
* @param queryName
* @return
*/
boolean hasQuery(String queryName);
/**
* Returns the named query with the given name or {@literal null} if none exists.
*
* @param queryName
* @return
*/
String getQuery(String queryName);
}

57
spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/PropertiesBasedNamedQueries.java

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
/*
* Copyright 2011 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.repository.core.support;
import java.util.Properties;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.util.Assert;
/**
* {@link NamedQueries} implementation backed by a {@link Properties} instance.
*
* @author Oliver Gierke
*/
public class PropertiesBasedNamedQueries implements NamedQueries {
public static NamedQueries EMPTY = new PropertiesBasedNamedQueries(new Properties());
private final Properties properties;
/**
* Creates a new {@link PropertiesBasedNamedQueries} for the given {@link Properties} instance.
*
* @param properties
*/
public PropertiesBasedNamedQueries(Properties properties) {
Assert.notNull(properties);
this.properties = properties;
}
/* (non-Javadoc)
* @see org.springframework.data.repository.core.NamedQueries#hasNamedQuery(java.lang.String)
*/
public boolean hasQuery(String queryName) {
return properties.containsKey(queryName);
}
/* (non-Javadoc)
* @see org.springframework.data.repository.core.NamedQueries#getNamedQuery(java.lang.String)
*/
public String getQuery(String queryName) {
return properties.getProperty(queryName);
}
}

22
spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java

@ -22,6 +22,7 @@ import org.springframework.beans.factory.InitializingBean; @@ -22,6 +22,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
@ -43,6 +44,7 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, @@ -43,6 +44,7 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
private Key queryLookupStrategyKey;
private Class<? extends T> repositoryInterface;
private Object customImplementation;
private NamedQueries namedQueries;
/**
@ -79,6 +81,15 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, @@ -79,6 +81,15 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
this.customImplementation = customImplementation;
}
/**
* Setter to inject a {@link NamedQueries} instance.
*
* @param namedQueries the namedQueries to set
*/
public void setNamedQueries(NamedQueries namedQueries) {
this.namedQueries = namedQueries;
}
/* (non-Javadoc)
* @see org.springframework.data.repository.support.EntityMetadataProvider#getEntityMetadata()
@ -135,15 +146,16 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, @@ -135,15 +146,16 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() {
this.factory = createRepositoryFactory();
this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);
this.factory.setNamedQueries(namedQueries);
}

14
spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java

@ -30,6 +30,7 @@ import org.springframework.aop.framework.ProxyFactory; @@ -30,6 +30,7 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryLookupStrategy;
@ -56,7 +57,7 @@ public abstract class RepositoryFactorySupport { @@ -56,7 +57,7 @@ public abstract class RepositoryFactorySupport {
private QueryLookupStrategy.Key queryLookupStrategyKey;
private List<QueryCreationListener<?>> queryPostProcessors =
new ArrayList<QueryCreationListener<?>>();
private NamedQueries namedQueries = PropertiesBasedNamedQueries.EMPTY;
/**
* Sets the strategy of how to lookup a query to execute finders.
@ -67,6 +68,15 @@ public abstract class RepositoryFactorySupport { @@ -67,6 +68,15 @@ public abstract class RepositoryFactorySupport {
this.queryLookupStrategyKey = key;
}
/**
* Configures a {@link NamedQueries} instance to be handed to the {@link QueryLookupStrategy} for query creation.
*
* @param namedQueries the namedQueries to set
*/
public void setNamedQueries(NamedQueries namedQueries) {
this.namedQueries = namedQueries == null ? PropertiesBasedNamedQueries.EMPTY : namedQueries;
}
/**
@ -291,7 +301,7 @@ public abstract class RepositoryFactorySupport { @@ -291,7 +301,7 @@ public abstract class RepositoryFactorySupport {
for (Method method : repositoryInformation.getQueryMethods()) {
RepositoryQuery query =
lookupStrategy.resolveQuery(method, repositoryInformation);
lookupStrategy.resolveQuery(method, repositoryInformation, namedQueries);
invokeListeners(query);
queries.put(method, query);
}

4
spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java

@ -18,6 +18,7 @@ package org.springframework.data.repository.query; @@ -18,6 +18,7 @@ package org.springframework.data.repository.query;
import java.lang.reflect.Method;
import java.util.Locale;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.util.StringUtils;
@ -56,7 +57,8 @@ public interface QueryLookupStrategy { @@ -56,7 +57,8 @@ public interface QueryLookupStrategy {
*
* @param method
* @param metadata
* @param namedQueries
* @return
*/
RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata);
RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries);
}

13
spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryMethod.java

@ -104,6 +104,19 @@ public class QueryMethod { @@ -104,6 +104,19 @@ public class QueryMethod {
};
}
/**
* Returns the name of the named query this method belongs to.
*
* @return
*/
public String getNamedQueryName() {
Class<?> domainClass = getDomainClass();
return String.format("%s.%s", domainClass.getSimpleName(),
method.getName());
}
protected Class<?> getDomainClass() {

7
spring-data-commons-core/src/main/resources/org/springframework/data/repository/config/spring-repository-1.0.xsd

@ -34,6 +34,13 @@ @@ -34,6 +34,13 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="named-queries-location" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the location to look for a Properties file containing externally defined queries.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="repository">

10
spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java

@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
*/
package org.springframework.data.repository.core.support;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.io.Serializable;
@ -28,12 +28,11 @@ import org.mockito.runners.MockitoJUnitRunner; @@ -28,12 +28,11 @@ import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.QueryCreationListener;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.RepositoryQuery;
/**
@ -89,6 +88,7 @@ public class RepositoryFactorySupportUnitTests { @@ -89,6 +88,7 @@ public class RepositoryFactorySupportUnitTests {
verify(backingRepo, times(0)).findOne(1);
}
class DummyRepositoryFactory extends RepositoryFactorySupport {
/* (non-Javadoc)
@ -123,7 +123,7 @@ public class RepositoryFactorySupportUnitTests { @@ -123,7 +123,7 @@ public class RepositoryFactorySupportUnitTests {
RepositoryQuery queryTwo = mock(RepositoryQuery.class);
QueryLookupStrategy strategy = mock(QueryLookupStrategy.class);
when(strategy.resolveQuery(any(Method.class), any(RepositoryMetadata.class)))
when(strategy.resolveQuery(any(Method.class), any(RepositoryMetadata.class), any(NamedQueries.class)))
.thenReturn(queryOne, queryTwo);
return strategy;

Loading…
Cancel
Save