@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2012 - 2013 the original author or authors .
* Copyright 2012 - 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 .
@ -16,10 +16,8 @@
@@ -16,10 +16,8 @@
package org.springframework.data.repository.support ;
import java.io.Serializable ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.List ;
import java.util.Map ;
@ -43,22 +41,25 @@ import org.springframework.util.ClassUtils;
@@ -43,22 +41,25 @@ import org.springframework.util.ClassUtils;
* Wrapper class to access repository instances obtained from a { @link ListableBeanFactory } .
*
* @author Oliver Gierke
* @author Thomas Darimont
* /
public class Repositories implements Iterable < Class < ? > > {
static final Repositories NONE = new Repositories ( ) ;
private final Map < Class < ? > , RepositoryFactoryInformation < Object , Serializable > > domainClassToBeanName = new HashMap < Class < ? > , RepositoryFactoryInformation < Object , Serializable > > ( ) ;
private final Map < RepositoryFactoryInformation < Object , Serializable > , String > repositories = new HashMap < RepositoryFactoryInformation < Object , Serializable > , String > ( ) ;
private static final RepositoryFactoryInformation < Object , Serializable > EMPTY_REPOSITORY_FACTORY_INFO = EmptyRepositoryFactoryInformation . INSTANCE ;
private final BeanFactory beanFactory ;
private final Set < String > repositoryFactoryBeanNames = new HashSet < String > ( ) ;
private final Map < Class < ? > , String > repositoryBeanNames ;
private final Map < Class < ? > , RepositoryFactoryInformation < Object , Serializable > > repositoryFactoryInfos ;
/ * *
* Constructor to create the { @link # NONE } instance .
* /
private Repositories ( ) {
this . beanFactory = null ;
this . repositoryBeanNames = Collections . < Class < ? > , String > emptyMap ( ) ;
this . repositoryFactoryInfos = Collections . < Class < ? > , RepositoryFactoryInformation < Object , Serializable > > emptyMap ( ) ;
}
/ * *
@ -70,11 +71,31 @@ public class Repositories implements Iterable<Class<?>> {
@@ -70,11 +71,31 @@ public class Repositories implements Iterable<Class<?>> {
public Repositories ( ListableBeanFactory factory ) {
Assert . notNull ( factory ) ;
this . beanFactory = factory ;
this . repositoryFactoryInfos = new HashMap < Class < ? > , RepositoryFactoryInformation < Object , Serializable > > ( ) ;
this . repositoryBeanNames = new HashMap < Class < ? > , String > ( ) ;
populateRepositoryFactoryInformation ( factory ) ;
}
@SuppressWarnings ( { "rawtypes" , "unchecked" } )
private void populateRepositoryFactoryInformation ( ListableBeanFactory factory ) {
String [ ] beanNamesForType = BeanFactoryUtils . beanNamesForTypeIncludingAncestors ( factory ,
RepositoryFactoryInformation . class , false , false ) ;
this . repositoryFactoryBeanNames . addAll ( Arrays . asList ( beanNamesForType ) ) ;
Set < Map . Entry < String , RepositoryFactoryInformation > > repositoryFactoryBeans = BeanFactoryUtils
. beansOfTypeIncludingAncestors ( factory , RepositoryFactoryInformation . class ) . entrySet ( ) ;
for ( Map . Entry < String , RepositoryFactoryInformation > entry : repositoryFactoryBeans ) {
String beanName = entry . getKey ( ) ;
RepositoryFactoryInformation repositoryFactoryInformation = entry . getValue ( ) ;
Class < ? > userDomainType = ClassUtils . getUserClass ( repositoryFactoryInformation . getRepositoryInformation ( )
. getDomainType ( ) ) ;
this . repositoryFactoryInfos . put ( userDomainType , repositoryFactoryInformation ) ;
this . repositoryBeanNames . put ( userDomainType , BeanFactoryUtils . transformedBeanName ( beanName ) ) ;
}
}
/ * *
@ -84,8 +105,10 @@ public class Repositories implements Iterable<Class<?>> {
@@ -84,8 +105,10 @@ public class Repositories implements Iterable<Class<?>> {
* @return
* /
public boolean hasRepositoryFor ( Class < ? > domainClass ) {
lookupRepositoryFactoryInformationFor ( domainClass ) ;
return domainClassToBeanName . containsKey ( domainClass ) ;
Assert . notNull ( domainClass , "Domain class must not be null!" ) ;
return repositoryFactoryInfos . containsKey ( domainClass ) ;
}
/ * *
@ -96,13 +119,27 @@ public class Repositories implements Iterable<Class<?>> {
@@ -96,13 +119,27 @@ public class Repositories implements Iterable<Class<?>> {
* /
public Object getRepositoryFor ( Class < ? > domainClass ) {
RepositoryFactoryInformation < Object , Serializable > information = getRepoInfoFor ( domainClass ) ;
Assert . notNull ( domainClass , "Domain class must not be null!" ) ;
if ( information = = null ) {
return null ;
}
String repositoryBeanName = repositoryBeanNames . get ( domainClass ) ;
return repositoryBeanName = = null | | beanFactory = = null ? null : beanFactory . getBean ( repositoryBeanName ) ;
}
/ * *
* Returns the { @link RepositoryFactoryInformation } for the given domain class . The given < code > code < / code > is
* converted to the actual user class if necessary , @see ClassUtils # getUserClass .
*
* @param domainClass must not be { @literal null } .
* @return the { @link RepositoryFactoryInformation } for the given domain class or { @literal null } if no repository
* registered for this domain class .
* /
private RepositoryFactoryInformation < Object , Serializable > getRepositoryFactoryInfoFor ( Class < ? > domainClass ) {
return beanFactory . getBean ( repositories . get ( information ) ) ;
Assert . notNull ( domainClass , "Domain class must not be null!" ) ;
RepositoryFactoryInformation < Object , Serializable > repositoryInfo = repositoryFactoryInfos . get ( ClassUtils
. getUserClass ( domainClass ) ) ;
return repositoryInfo = = null ? EMPTY_REPOSITORY_FACTORY_INFO : repositoryInfo ;
}
/ * *
@ -114,8 +151,9 @@ public class Repositories implements Iterable<Class<?>> {
@@ -114,8 +151,9 @@ public class Repositories implements Iterable<Class<?>> {
@SuppressWarnings ( "unchecked" )
public < T , S extends Serializable > EntityInformation < T , S > getEntityInformationFor ( Class < ? > domainClass ) {
RepositoryFactoryInformation < Object , Serializable > information = getRepoInfoFor ( domainClass ) ;
return information = = null ? null : ( EntityInformation < T , S > ) information . getEntityInformation ( ) ;
Assert . notNull ( domainClass , "Domain class must not be null!" ) ;
return ( EntityInformation < T , S > ) getRepositoryFactoryInfoFor ( domainClass ) . getEntityInformation ( ) ;
}
/ * *
@ -127,8 +165,10 @@ public class Repositories implements Iterable<Class<?>> {
@@ -127,8 +165,10 @@ public class Repositories implements Iterable<Class<?>> {
* /
public RepositoryInformation getRepositoryInformationFor ( Class < ? > domainClass ) {
RepositoryFactoryInformation < Object , Serializable > information = getRepoInfoFor ( domainClass ) ;
return information = = null ? null : information . getRepositoryInformation ( ) ;
Assert . notNull ( domainClass , "Domain class must not be null!" ) ;
RepositoryFactoryInformation < Object , Serializable > information = getRepositoryFactoryInfoFor ( domainClass ) ;
return information = = EMPTY_REPOSITORY_FACTORY_INFO ? null : information . getRepositoryInformation ( ) ;
}
/ * *
@ -141,8 +181,8 @@ public class Repositories implements Iterable<Class<?>> {
@@ -141,8 +181,8 @@ public class Repositories implements Iterable<Class<?>> {
* /
public PersistentEntity < ? , ? > getPersistentEntity ( Class < ? > domainClass ) {
RepositoryFactoryInformation < Object , Serializable > information = getRepoInfoFor ( domainClass ) ;
return information = = null ? null : information . getPersistentEntity ( ) ;
Assert . notNull ( domainClass , "Domain class must not be null!" ) ;
return getRepositoryFactoryInfoFor ( domainClass ) . getPersistentEntity ( ) ;
}
/ * *
@ -153,14 +193,13 @@ public class Repositories implements Iterable<Class<?>> {
@@ -153,14 +193,13 @@ public class Repositories implements Iterable<Class<?>> {
* /
public List < QueryMethod > getQueryMethodsFor ( Class < ? > domainClass ) {
RepositoryFactoryInformation < Object , Serializable > information = getRepoInfoFor ( domainClass ) ;
return information = = null ? Collections . < QueryMethod > emptyList ( ) : information . getQueryMethods ( ) ;
Assert . notNull ( domainClass , "Domain class must not be null!" ) ;
return getRepositoryFactoryInfoFor ( domainClass ) . getQueryMethods ( ) ;
}
@SuppressWarnings ( "unchecked" )
public < T > CrudInvoker < T > getCrudInvoker ( Class < T > domainClass ) {
RepositoryInformation information = getRepositoryInformationFor ( domainClass ) ;
Object repository = getRepositoryFor ( domainClass ) ;
Assert . notNull ( repository , String . format ( "No repository found for domain class: %s" , domainClass ) ) ;
@ -168,67 +207,45 @@ public class Repositories implements Iterable<Class<?>> {
@@ -168,67 +207,45 @@ public class Repositories implements Iterable<Class<?>> {
if ( repository instanceof CrudRepository ) {
return new CrudRepositoryInvoker < T > ( ( CrudRepository < T , Serializable > ) repository ) ;
} else {
return new ReflectionRepositoryInvoker < T > ( repository , information . getCrudMethods ( ) ) ;
return new ReflectionRepositoryInvoker < T > ( repository , getRepos itoryI nformationFor ( domainClass ) . getCrudMethods ( ) ) ;
}
}
private RepositoryFactoryInformation < Object , Serializable > getRepoInfoFor ( Class < ? > domainClass ) {
Assert . notNull ( domainClass ) ;
// Create defensive copy of the keys to allow threads to potentially add values while iterating over them
Set < RepositoryFactoryInformation < Object , Serializable > > keys = Collections . unmodifiableSet ( repositories . keySet ( ) ) ;
Class < ? > type = ClassUtils . getUserClass ( domainClass ) ;
for ( RepositoryFactoryInformation < Object , Serializable > information : keys ) {
if ( type . equals ( information . getEntityInformation ( ) . getJavaType ( ) ) ) {
return information ;
}
}
return lookupRepositoryFactoryInformationFor ( type ) ;
}
/ *
* ( non - Javadoc )
* @see java . lang . Iterable # iterator ( )
* /
public Iterator < Class < ? > > iterator ( ) {
lookupRepositoryFactoryInformationFor ( null ) ;
return domainClassToBeanName . keySet ( ) . iterator ( ) ;
return repositoryFactoryInfos . keySet ( ) . iterator ( ) ;
}
/ * *
* Looks up the { @link RepositoryFactoryInformation } for a given domain type . Will inspect the { @link BeanFactory } for
* beans implementing { @link RepositoryFactoryInformation } and cache the domain class to repository bean name mappings
* for further lookups . If a { @link RepositoryFactoryInformation } for the given domain type is found we interrupt the
* lookup proces to prevent beans from being looked up early .
* Null - object to avoid nasty { @literal null } checks in cache lookups .
*
* @param domainType
* @return
* @author Thomas Darimont
* /
@SuppressWarnings ( "unchecked" )
private RepositoryFactoryInformation < Object , Serializable > lookupRepositoryFactoryInformationFor ( Class < ? > domainType ) {
if ( domainClassToBeanName . containsKey ( domainType ) ) {
return domainClassToBeanName . get ( domainType ) ;
}
private static enum EmptyRepositoryFactoryInformation implements RepositoryFactoryInformation < Object , Serializable > {
for ( String repositoryFactoryName : repositoryFactoryBeanNames ) {
INSTANCE ;
RepositoryFactoryInformation < Object , Serializable > information = beanFactory . getBean ( repositoryFactoryName ,
RepositoryFactoryInformation . class ) ;
RepositoryInformation info = information . getRepositoryInformation ( ) ;
@Override
public EntityInformation < Object , Serializable > getEntityInformation ( ) {
return null ;
}
repositories . put ( information , BeanFactoryUtils . transformedBeanName ( repositoryFactoryName ) ) ;
domainClassToBeanName . put ( info . getDomainType ( ) , information ) ;
@Override
public RepositoryInformation getRepositoryInformation ( ) {
return null ;
}
if ( info . getDomainType ( ) . equals ( domainType ) ) {
return information ;
}
@Override
public PersistentEntity < ? , ? > getPersistentEntity ( ) {
return null ;
}
return null ;
@Override
public List < QueryMethod > getQueryMethods ( ) {
return Collections . < QueryMethod > emptyList ( ) ;
}
}
}