DATACMNS-159 - Improve reference documentation on repository extensions.
Updated section covering adding custom behavior to all repositories to better match what is in the actual code base.
This commit is contained in:
committed by
Oliver Gierke
parent
6a461c0a51
commit
a0bec0fce0
@@ -23,6 +23,15 @@
|
||||
interfaces of Spring Data repositories in general for detailled
|
||||
information on the specific features of a particular store consult the
|
||||
later chapters of this document.</para>
|
||||
|
||||
<note>
|
||||
<para>As this part of the documentation is pulled in from Spring Data
|
||||
Commons we have to decide for a particular module to be used as example.
|
||||
The configuration and code samples in this chapter are using the JPA
|
||||
module. Make sure you adapt e.g. the XML namespace declaration, types to
|
||||
be extended to the equivalents of the module you're actually
|
||||
using.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="repositories.core-concepts">
|
||||
@@ -664,7 +673,8 @@ UserRepository repository = factory.getRepository(UserRepository.class);</progra
|
||||
<example>
|
||||
<title>An interface declaring custom shared behaviour</title>
|
||||
|
||||
<para><programlisting language="java">public interface MyRepository<T, ID extends Serializable>
|
||||
<para><programlisting language="java">
|
||||
public interface MyRepository<T, ID extends Serializable>
|
||||
extends JpaRepository<T, ID> {
|
||||
|
||||
void sharedCustomMethod(ID id);
|
||||
@@ -672,59 +682,93 @@ UserRepository repository = factory.getRepository(UserRepository.class);</progra
|
||||
</example>
|
||||
|
||||
<para>Now your individual repository interfaces will extend this
|
||||
intermediate interface to include the functionality declared. The second
|
||||
step is to create an implementation of this interface that extends the
|
||||
persistence technology specific repository base class which will act as
|
||||
custom base class for the repository proxies then.</para>
|
||||
intermediate interface instead of the
|
||||
<interfacename>Repository</interfacename> interface to include the
|
||||
functionality declared. The second step is to create an implementation
|
||||
of this interface that extends the persistence technology specific
|
||||
repository base class which will then act as a custom base class for the
|
||||
repository proxies.</para>
|
||||
|
||||
<note>
|
||||
<para>If you're using automatic repository interface detection using
|
||||
the Spring namespace using the interface just as is will cause Spring
|
||||
to create an instance of <interfacename>MyRepository</interfacename>.
|
||||
This is of course not desired as it just acts as intermediary between
|
||||
<interfacename>Repository</interfacename> and the actual repository
|
||||
interfaces you want to define for each entity. To exclude an interface
|
||||
extending <interfacename>Repository</interfacename> from being
|
||||
instantiated as repository instance annotate it with
|
||||
<interfacename>@NoRepositoryBean</interfacename>.</para>
|
||||
<para>The default behaviour of the Spring <code><repositories
|
||||
/></code> namespace is to provide an implementation for all
|
||||
interfaces that fall under the <code>base-package</code>. This means
|
||||
that if left in it's current state, an implementation instance of
|
||||
<interfacename>MyRepository</interfacename> will be created by Spring.
|
||||
This is of course not desired as it is just supposed to act as an
|
||||
intermediary between <interfacename>Repository</interfacename> and the
|
||||
actual repository interfaces you want to define for each entity. To
|
||||
exclude an interface extending
|
||||
<interfacename>Repository</interfacename> from being instantiated as a
|
||||
repository instance it can either be annotate it with
|
||||
<interfacename>@NoRepositoryBean</interfacename> or moved out side of
|
||||
the configured <code>base-package</code>.</para>
|
||||
</note>
|
||||
|
||||
<example>
|
||||
<title>Custom repository base class</title>
|
||||
|
||||
<programlisting language="java">public class MyRepositoryImpl<T, ID extends Serializable>
|
||||
<programlisting language="java">
|
||||
public class MyRepositoryImpl<T, ID extends Serializable>
|
||||
extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
|
||||
|
||||
private EntityManager entityManager;
|
||||
|
||||
// There are two constructors to choose from, either can be used.
|
||||
public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
|
||||
super(domainClass, entityManager);
|
||||
|
||||
// This is the recommended method for accessing inherited class dependencies.
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
public void sharedCustomMethod(ID id) {
|
||||
// implementation goes here
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>The last step to get this implementation used as base class for
|
||||
Spring Data repositories is replacing the standard
|
||||
<classname>RepositoryFactoryBean</classname> with a custom one using a
|
||||
custom <classname>RepositoryFactory</classname> that in turn creates
|
||||
instances of your <classname>MyRepositoryImpl</classname> class.</para>
|
||||
<para>The last step is to create a custom repository factory to replace
|
||||
the default <classname>RepositoryFactoryBean</classname> that will in
|
||||
turn produce a custom <classname>RepositoryFactory</classname>. The new
|
||||
repository factory will then provide your
|
||||
<classname>MyRepositoryImpl</classname> as the implementation of any
|
||||
interfaces that extend the <interfacename>Repository</interfacename>
|
||||
interface, replacing the <classname>SimpleJpaRepository</classname>
|
||||
implementation you just extended.</para>
|
||||
|
||||
<example>
|
||||
<title>Custom repository factory bean</title>
|
||||
|
||||
<programlisting language="java">public class MyRepositoryFactoryBean<T extends JpaRepository<?, ?>
|
||||
extends JpaRepositoryFactoryBean<T> {
|
||||
<programlisting language="java">
|
||||
public class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
|
||||
extends JpaRepositoryFactoryBean<R, T, I> {
|
||||
|
||||
protected RepositoryFactorySupport getRepositoryFactory(…) {
|
||||
return new MyRepositoryFactory(…);
|
||||
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
|
||||
|
||||
return new MyRepositoryFactory(entityManager);
|
||||
}
|
||||
|
||||
private static class MyRepositoryFactory extends JpaRepositoryFactory{
|
||||
private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
|
||||
|
||||
public MyRepositoryImpl getTargetRepository(…) {
|
||||
return new MyRepositoryImpl(…);
|
||||
private EntityManager entityManager;
|
||||
|
||||
public MyRepositoryFactory(EntityManager entityManager) {
|
||||
super(entityManager);
|
||||
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
public Class<? extends RepositorySupport> getRepositoryClass() {
|
||||
return MyRepositoryImpl.class;
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
|
||||
return new MyRepositoryImpl<T, I>((Class<T>) metadata.getDomainClass(), entityManager);
|
||||
}
|
||||
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
|
||||
// The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
|
||||
//to check for QueryDslJpaRepository's which is out of scope.
|
||||
return MyRepository.class;
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
Reference in New Issue
Block a user