DATACMNS-542 - Simplified way to customize repository base class.

RepositoryFactorySupport now exposes a setRepositoryBaseClass(…) to take a custom type that instances will be created reflectively for. This removes the need for a boilerplate repository factory and FactoryBean implementation to hook custom repository base class implementations into the infrastructure.

RepositoryFactorySupport now exposes a getTargetRepositoryViaReflection(…) method to allow sub-classes to create repository instances and consider customized repository base classes nonetheless. getTargetRepository(…) needs a tiny signature change which unfortunately requires imple

Fixed schema registration for version 1.8 schema. Added new XSD containing a base-class attribute on the <repositories /> element to customize the repository base class via XML.

Removed outdated section of how to create a custom base repository class from the reference documentation and replaced it with new simplified instructions.

Deprecated usage of factory-class attribute in configuration. Point users to newly introduced way of configuring a base class directly to avoid the need for a boilerplate repository factory and factory bean implementation.

DefaultRepositoryInformation now makes target class methods assignable before caching and returning them, so that they can always be invoked reflectively. Made this aspect part of the contract of RepositoryInformation.getTargetClassMethod(…).
This commit is contained in:
Oliver Gierke
2015-02-24 21:08:23 +01:00
parent af2e1c50c3
commit 2d62c149bb
18 changed files with 522 additions and 79 deletions

View File

@@ -21,6 +21,7 @@ import java.lang.annotation.RetentionPolicy;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Import;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupportUnitTests.DummyRegistrar;
import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean;
@@ -41,6 +42,8 @@ public @interface EnableRepositories {
Class<?> repositoryFactoryBeanClass() default DummyRepositoryFactoryBean.class;
Class<?> repositoryBaseClass() default PagingAndSortingRepository.class;
String namedQueriesLocation() default "";
String repositoryImplementationPostfix() default "Impl";

View File

@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
import org.mockito.Mockito;
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.core.support.RepositoryFactorySupportUnitTests.MyRepositoryQuery;
import org.springframework.data.repository.query.QueryLookupStrategy;
@@ -67,7 +68,7 @@ public class DummyRepositoryFactory extends RepositoryFactorySupport {
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)
*/
@Override
protected Object getTargetRepository(RepositoryMetadata metadata) {
protected Object getTargetRepository(RepositoryInformation information) {
return repository;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2015 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.
@@ -18,6 +18,7 @@ package org.springframework.data.util;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import org.junit.Before;
@@ -31,11 +32,13 @@ import org.springframework.util.ReflectionUtils.FieldFilter;
*/
public class ReflectionUtilsUnitTests {
@SuppressWarnings("rawtypes") Constructor constructor;
Field reference;
@Before
public void setUp() throws Exception {
this.reference = Sample.class.getField("field");
this.constructor = ConstructorDetection.class.getConstructor(int.class, String.class);
}
@Test
@@ -84,12 +87,43 @@ public class ReflectionUtilsUnitTests {
assertThat(sample.first, is("foo"));
}
/**
* @see DATACMNS-542
*/
@Test
public void detectsConstructorForCompleteMatch() throws Exception {
assertThat(ReflectionUtils.findConstructor(ConstructorDetection.class, 2, "test"), is(constructor));
}
/**
* @see DATACMNS-542
*/
@Test
public void detectsConstructorForMatchWithNulls() throws Exception {
assertThat(ReflectionUtils.findConstructor(ConstructorDetection.class, 2, null), is(constructor));
}
/**
* @see DATACMNS-542
*/
@Test
public void rejectsConstructorIfNumberOfArgumentsDontMatch() throws Exception {
assertThat(ReflectionUtils.findConstructor(ConstructorDetection.class, 2, "test", "test"), is(nullValue()));
}
/**
* @see DATACMNS-542
*/
@Test
public void rejectsConstructorForNullForPrimitiveArgument() throws Exception {
assertThat(ReflectionUtils.findConstructor(ConstructorDetection.class, null, "test"), is(nullValue()));
}
static class Sample {
public String field;
@Autowired
String first, second;
@Autowired String first, second;
}
static class FieldNameFieldFilter implements DescribedFieldFilter {
@@ -108,4 +142,8 @@ public class ReflectionUtilsUnitTests {
return String.format("Filter for fields named %s", name);
}
}
static class ConstructorDetection {
public ConstructorDetection(int i, String string) {}
}
}