DATACMNS-406 - Tighten contract for RepositoryMetadata implementations.

We now resolve the domain and id-types eagerly within the constructor of AbstractRepositoryMetadata implementations to prevent a RepositoryMetadata instance to be created in an invalid state. Pulled-up repositoryInterface property to AbstractRepositoryMetadata.

Original pull request: #58.
This commit is contained in:
Thomas Darimont
2013-11-20 15:25:37 +01:00
committed by Oliver Gierke
parent 09b8989a7f
commit b96f613b98
6 changed files with 118 additions and 60 deletions

View File

@@ -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.
@@ -26,10 +26,12 @@ import org.springframework.util.Assert;
* Base class for {@link RepositoryMetadata} implementations.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public abstract class AbstractRepositoryMetadata implements RepositoryMetadata {
private final TypeInformation<?> typeInformation;
private final Class<?> repositoryInterface;
/**
* Creates a new {@link AbstractRepositoryMetadata}.
@@ -40,6 +42,8 @@ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata {
Assert.notNull(repositoryInterface, "Given type must not be null!");
Assert.isTrue(repositoryInterface.isInterface(), "Given type must be an interface!");
this.repositoryInterface = repositoryInterface;
this.typeInformation = ClassTypeInformation.from(repositoryInterface);
}
@@ -54,4 +58,11 @@ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata {
return Iterable.class.isAssignableFrom(rawType) ? returnTypeInfo.getComponentType().getType() : rawType;
}
/* (non-Javadoc)
* @see org.springframework.data.repository.core.RepositoryMetadata#getRepositoryInterface()
*/
public Class<?> getRepositoryInterface() {
return this.repositoryInterface;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 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.
@@ -26,13 +26,15 @@ import org.springframework.util.Assert;
* {@link RepositoryDefinition} annotation.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class AnnotationRepositoryMetadata extends AbstractRepositoryMetadata {
private static final String NO_ANNOTATION_FOUND = String.format("Interface must be annotated with @%s!",
RepositoryDefinition.class.getName());
private final Class<?> repositoryInterface;
private final Class<? extends Serializable> idType;
private final Class<?> domainType;
/**
* Creates a new {@link AnnotationRepositoryMetadata} instance looking up repository types from a
@@ -41,34 +43,59 @@ public class AnnotationRepositoryMetadata extends AbstractRepositoryMetadata {
* @param repositoryInterface must not be {@literal null}.
*/
public AnnotationRepositoryMetadata(Class<?> repositoryInterface) {
super(repositoryInterface);
Assert.isTrue(repositoryInterface.isAnnotationPresent(RepositoryDefinition.class), NO_ANNOTATION_FOUND);
this.repositoryInterface = repositoryInterface;
this.idType = resolveIdType(repositoryInterface);
this.domainType = resolveDomainType(repositoryInterface);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
* @see org.springframework.data.repository.core.RepositoryMetadata#getIdType()
*/
@Override
public Class<? extends Serializable> getIdType() {
RepositoryDefinition annotation = repositoryInterface.getAnnotation(RepositoryDefinition.class);
return annotation == null ? null : annotation.idClass();
return this.idType;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
* @see org.springframework.data.repository.core.RepositoryMetadata#getDomainType()
*/
@Override
public Class<?> getDomainType() {
RepositoryDefinition annotation = repositoryInterface.getAnnotation(RepositoryDefinition.class);
return annotation == null ? null : annotation.domainClass();
return this.domainType;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
/**
* @param repositoryInterface must not be {@literal null}.
* @return the resolved domain type, never {@literal null}.
*/
public Class<?> getRepositoryInterface() {
return repositoryInterface;
private Class<? extends Serializable> resolveIdType(Class<?> repositoryInterface) {
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
RepositoryDefinition annotation = repositoryInterface.getAnnotation(RepositoryDefinition.class);
Assert.isTrue(annotation != null && annotation.idClass() != null,
String.format("Could not resolve id type of %s!", repositoryInterface));
return annotation.idClass();
}
/**
* @param repositoryInterface must not be {@literal null}.
* @return the resolved domain type, never {@literal null}.
*/
private Class<?> resolveDomainType(Class<?> repositoryInterface) {
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
RepositoryDefinition annotation = repositoryInterface.getAnnotation(RepositoryDefinition.class);
Assert.isTrue(annotation != null && annotation.domainClass() != null,
String.format("Could not resolve domain type of %s!", repositoryInterface));
return annotation.domainClass();
}
}

View File

@@ -42,6 +42,7 @@ import org.springframework.util.ClassUtils;
* Default implementation of {@link RepositoryInformation}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements RepositoryInformation {
@@ -78,15 +79,6 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
this.crudMethods = new DefaultCrudMethods(this);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
*/
@Override
public Class<?> getRepositoryInterface() {
return metadata.getRepositoryInterface();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 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.
@@ -28,10 +28,15 @@ import org.springframework.util.Assert;
* about domain and id class.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class DefaultRepositoryMetadata extends AbstractRepositoryMetadata {
private final Class<?> repositoryInterface;
private static final String MUST_BE_A_REPOSITORY = String.format("Given type must be assignable to %s!",
Repository.class);
private final Class<? extends Serializable> idType;
private final Class<?> domainType;
/**
* Creates a new {@link DefaultRepositoryMetadata} for the given repository interface.
@@ -41,38 +46,57 @@ public class DefaultRepositoryMetadata extends AbstractRepositoryMetadata {
public DefaultRepositoryMetadata(Class<?> repositoryInterface) {
super(repositoryInterface);
Assert.isTrue(repositoryInterface.isInterface());
Assert.isTrue(Repository.class.isAssignableFrom(repositoryInterface));
this.repositoryInterface = repositoryInterface;
Assert.isTrue(Repository.class.isAssignableFrom(repositoryInterface), MUST_BE_A_REPOSITORY);
this.idType = resolveIdType(repositoryInterface);
this.domainType = resolveDomainType(repositoryInterface);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
*/
public Class<?> getRepositoryInterface() {
return repositoryInterface;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
* @see org.springframework.data.repository.core.RepositoryMetadata#getDomainType()
*/
@Override
public Class<?> getDomainType() {
Class<?>[] arguments = resolveTypeArguments(repositoryInterface, Repository.class);
return arguments == null ? null : arguments[0];
return this.domainType;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
* @see org.springframework.data.repository.core.RepositoryMetadata#getIdType()
*/
@SuppressWarnings("unchecked")
@Override
public Class<? extends Serializable> getIdType() {
return this.idType;
}
/**
* @param repositoryInterface must not be {@literal null}.
* @return the resolved domain type, never {@literal null}.
*/
private Class<?> resolveDomainType(Class<?> repositoryInterface) {
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
Class<?>[] arguments = resolveTypeArguments(repositoryInterface, Repository.class);
return (Class<? extends Serializable>) (arguments == null ? null : arguments[1]);
Assert.isTrue(arguments != null && arguments[0] != null,
String.format("Could not resolve domain type of %s!", repositoryInterface));
return arguments[0];
}
/**
* @param repositoryInterface must not be {@literal null}.
* @return the resolved id type, never {@literal null}.
*/
private Class<? extends Serializable> resolveIdType(Class<?> repositoryInterface) {
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
Class<?>[] arguments = resolveTypeArguments(repositoryInterface, Repository.class);
Assert.isTrue(arguments != null && arguments[1] != null,
String.format("Could not resolve id type of %s!", repositoryInterface));
return (Class<? extends Serializable>) arguments[1];
}
}