Formatting.

This commit is contained in:
Oliver Gierke
2011-09-01 18:15:09 +02:00
parent 112127d35f
commit 7126b11173
105 changed files with 1215 additions and 1926 deletions

View File

@@ -25,6 +25,6 @@ import java.lang.annotation.Target;
* @author J. Brisbin <jbrisbin@vmware.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD})
@Target(value = { ElementType.FIELD })
public @interface Id {
}

View File

@@ -25,11 +25,6 @@ import java.lang.annotation.Target;
* @author J. Brisbin <jbrisbin@vmware.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {
ElementType.TYPE,
ElementType.ANNOTATION_TYPE,
ElementType.FIELD,
ElementType.PARAMETER
})
@Target(value = { ElementType.TYPE, ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.PARAMETER })
public @interface Persistent {
}

View File

@@ -25,9 +25,6 @@ import java.lang.annotation.Target;
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.ANNOTATION_TYPE,
ElementType.FIELD
})
@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD })
public @interface Reference {
}

View File

@@ -67,7 +67,7 @@ public class UserCredentials {
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
@@ -88,12 +88,12 @@ public class UserCredentials {
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * ObjectUtils.nullSafeHashCode(username);
result += 31 * ObjectUtils.nullSafeHashCode(password);
return result;
}
}

View File

@@ -19,13 +19,11 @@ import java.io.Serializable;
import org.joda.time.DateTime;
/**
* Interface for auditable entities. Allows storing and retrieving creation and
* modification information. The changing instance (typically some user) is to
* be defined by a generics definition.
*
* @param <U> the auditing type. Typically some kind of user.
* Interface for auditable entities. Allows storing and retrieving creation and modification information. The changing
* instance (typically some user) is to be defined by a generics definition.
*
* @param <U> the auditing type. Typically some kind of user.
* @param <ID> the type of the auditing type's idenifier
* @author Oliver Gierke
*/
@@ -33,63 +31,56 @@ public interface Auditable<U, ID extends Serializable> extends Persistable<ID> {
/**
* Returns the user who created this entity.
*
*
* @return the createdBy
*/
U getCreatedBy();
/**
* Sets the user who created this entity.
*
*
* @param createdBy the creating entity to set
*/
void setCreatedBy(final U createdBy);
/**
* Returns the creation date of the entity.
*
*
* @return the createdDate
*/
DateTime getCreatedDate();
/**
* Sets the creation date of the entity.
*
*
* @param creationDate the creation date to set
*/
void setCreatedDate(final DateTime creationDate);
/**
* Returns the user who modified the entity lastly.
*
*
* @return the lastModifiedBy
*/
U getLastModifiedBy();
/**
* Sets the user who modified the entity lastly.
*
*
* @param lastModifiedBy the last modifying entity to set
*/
void setLastModifiedBy(final U lastModifiedBy);
/**
* Returns the date of the last modification.
*
*
* @return the lastModifiedDate
*/
DateTime getLastModifiedDate();
/**
* Sets the date of the last modification.
*
*
* @param lastModifiedDate the date of the last modification to set
*/
void setLastModifiedDate(final DateTime lastModifiedDate);

View File

@@ -16,9 +16,8 @@
package org.springframework.data.domain;
/**
* Interface for components that are aware of the application's current auditor.
* This will be some kind of user mostly.
*
* Interface for components that are aware of the application's current auditor. This will be some kind of user mostly.
*
* @param <T> the type of the auditing instance
* @author Oliver Gierke
*/
@@ -26,7 +25,7 @@ public interface AuditorAware<T> {
/**
* Returns the current auditor of the application.
*
*
* @return the current auditor
*/
T getCurrentAuditor();

View File

@@ -18,89 +18,78 @@ package org.springframework.data.domain;
import java.util.Iterator;
import java.util.List;
/**
* A page is a sublist of a list of objects. It allows gain information about
* the position of it in the containing entire list.
*
* A page is a sublist of a list of objects. It allows gain information about the position of it in the containing
* entire list.
*
* @param <T>
* @author Oliver Gierke
*/
public interface Page<T> extends Iterable<T> {
/**
* Returns the number of the current page. Is always positive and less that
* {@code Page#getTotalPages()}.
*
* Returns the number of the current page. Is always positive and less that {@code Page#getTotalPages()}.
*
* @return the number of the current page
*/
int getNumber();
/**
* Returns the size of the page.
*
*
* @return the size of the page
*/
int getSize();
/**
* Returns the number of total pages.
*
*
* @return the number of toral pages
*/
int getTotalPages();
/**
* Returns the number of elements currently on this page.
*
*
* @return the number of elements currently on this page
*/
int getNumberOfElements();
/**
* Returns the total amount of elements.
*
*
* @return the total amount of elements
*/
long getTotalElements();
/**
* Returns if there is a previous page.
*
*
* @return if there is a previous page
*/
boolean hasPreviousPage();
/**
* Returns whether the current page is the first one.
*
*
* @return
*/
boolean isFirstPage();
/**
* Returns if there is a next page.
*
*
* @return if there is a next page
*/
boolean hasNextPage();
/**
* Returns whether the current page is the last one.
*
*
* @return
*/
boolean isLastPage();
/*
* (non-Javadoc)
*
@@ -108,26 +97,23 @@ public interface Page<T> extends Iterable<T> {
*/
Iterator<T> iterator();
/**
* Returns the page content as {@link List}.
*
*
* @return
*/
List<T> getContent();
/**
* Returns whether the {@link Page} has content at all.
*
*
* @return
*/
boolean hasContent();
/**
* Returns the sorting parameters for the page.
*
*
* @return
*/
Sort getSort();

View File

@@ -21,10 +21,9 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Basic {@code Page} implementation.
*
*
* @param <T> the type of which the page consists.
* @author Oliver Gierke
*/
@@ -36,13 +35,12 @@ public class PageImpl<T> implements Page<T>, Serializable {
private final Pageable pageable;
private final long total;
/**
* Constructor of {@code PageImpl}.
*
* @param content the content of this page
*
* @param content the content of this page
* @param pageable the paging information
* @param total the total amount of items available
* @param total the total amount of items available
*/
public PageImpl(List<T> content, Pageable pageable, long total) {
@@ -55,11 +53,10 @@ public class PageImpl<T> implements Page<T>, Serializable {
this.pageable = pageable;
}
/**
* Creates a new {@link PageImpl} with the given content. This will result
* in the created {@link Page} being identical to the entire {@link List}.
*
* Creates a new {@link PageImpl} with the given content. This will result in the created {@link Page} being identical
* to the entire {@link List}.
*
* @param content
*/
public PageImpl(List<T> content) {
@@ -67,7 +64,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
this(content, null, (null == content) ? 0 : content.size());
}
/*
* (non-Javadoc)
*
@@ -78,7 +74,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return pageable == null ? 0 : pageable.getPageNumber();
}
/*
* (non-Javadoc)
*
@@ -89,7 +84,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return pageable == null ? 0 : pageable.getPageSize();
}
/*
* (non-Javadoc)
*
@@ -100,7 +94,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return getSize() == 0 ? 0 : (int) Math.ceil((double) total / (double) getSize());
}
/*
* (non-Javadoc)
*
@@ -111,7 +104,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return content.size();
}
/*
* (non-Javadoc)
*
@@ -122,7 +114,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return total;
}
/*
* (non-Javadoc)
*
@@ -133,7 +124,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return getNumber() > 0;
}
/*
* (non-Javadoc)
*
@@ -144,7 +134,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return !hasPreviousPage();
}
/*
* (non-Javadoc)
*
@@ -155,7 +144,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return ((getNumber() + 1) * getSize()) < total;
}
/*
* (non-Javadoc)
*
@@ -166,7 +154,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return !hasNextPage();
}
/*
* (non-Javadoc)
*
@@ -177,7 +164,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return content.iterator();
}
/*
* (non-Javadoc)
*
@@ -198,7 +184,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return !content.isEmpty();
}
/*
* (non-Javadoc)
*
@@ -209,7 +194,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return pageable == null ? null : pageable.getSort();
}
/*
* (non-Javadoc)
*
@@ -224,11 +208,9 @@ public class PageImpl<T> implements Page<T>, Serializable {
contentType = content.get(0).getClass().getName();
}
return String.format("Page %s of %d containing %s instances",
getNumber(), getTotalPages(), contentType);
return String.format("Page %s of %d containing %s instances", getNumber(), getTotalPages(), contentType);
}
/*
* (non-Javadoc)
*
@@ -254,7 +236,6 @@ public class PageImpl<T> implements Page<T>, Serializable {
return totalEqual && contentEqual && pageableEqual;
}
/*
* (non-Javadoc)
*

View File

@@ -19,10 +19,9 @@ import java.io.Serializable;
import org.springframework.data.domain.Sort.Direction;
/**
* Basic Java Bean implementation of {@code Pageable}.
*
*
* @author Oliver Gierke
*/
public class PageRequest implements Pageable, Serializable {
@@ -33,11 +32,10 @@ public class PageRequest implements Pageable, Serializable {
private final int size;
private final Sort sort;
/**
* Creates a new {@link PageRequest}. Pages are zero indexed, thus providing
* 0 for {@code page} will return the first page.
*
* Creates a new {@link PageRequest}. Pages are zero indexed, thus providing 0 for {@code page} will return the first
* page.
*
* @param size
* @param page
*/
@@ -46,25 +44,22 @@ public class PageRequest implements Pageable, Serializable {
this(page, size, null);
}
/**
* Creates a new {@link PageRequest} with sort parameters applied.
*
*
* @param page
* @param size
* @param direction
* @param properties
*/
public PageRequest(int page, int size, Direction direction,
String... properties) {
public PageRequest(int page, int size, Direction direction, String... properties) {
this(page, size, new Sort(direction, properties));
}
/**
* Creates a new {@link PageRequest} with sort parameters applied.
*
*
* @param page
* @param size
* @param sort
@@ -72,13 +67,11 @@ public class PageRequest implements Pageable, Serializable {
public PageRequest(int page, int size, Sort sort) {
if (0 > page) {
throw new IllegalArgumentException(
"Page index must not be less than zero!");
throw new IllegalArgumentException("Page index must not be less than zero!");
}
if (0 >= size) {
throw new IllegalArgumentException(
"Page size must not be less than or equal to zero!");
throw new IllegalArgumentException("Page size must not be less than or equal to zero!");
}
this.page = page;
@@ -86,7 +79,6 @@ public class PageRequest implements Pageable, Serializable {
this.sort = sort;
}
/*
* (non-Javadoc)
*
@@ -97,7 +89,6 @@ public class PageRequest implements Pageable, Serializable {
return size;
}
/*
* (non-Javadoc)
*
@@ -108,7 +99,6 @@ public class PageRequest implements Pageable, Serializable {
return page;
}
/*
* (non-Javadoc)
*
@@ -119,7 +109,6 @@ public class PageRequest implements Pageable, Serializable {
return page * size;
}
/*
* (non-Javadoc)
*
@@ -130,7 +119,6 @@ public class PageRequest implements Pageable, Serializable {
return sort;
}
/*
* (non-Javadoc)
*
@@ -152,14 +140,11 @@ public class PageRequest implements Pageable, Serializable {
boolean pageEqual = this.page == that.page;
boolean sizeEqual = this.size == that.size;
boolean sortEqual =
this.sort == null ? that.sort == null : this.sort
.equals(that.sort);
boolean sortEqual = this.sort == null ? that.sort == null : this.sort.equals(that.sort);
return pageEqual && sizeEqual && sortEqual;
}
/*
* (non-Javadoc)
*

View File

@@ -17,39 +17,35 @@ package org.springframework.data.domain;
/**
* Abstract interface for pagination information.
*
*
* @author Oliver Gierke
*/
public interface Pageable {
/**
* Returns the page to be returned.
*
*
* @return the page to be returned.
*/
int getPageNumber();
/**
* Returns the number of items to be returned.
*
*
* @return the number of items of that page
*/
int getPageSize();
/**
* Returns the offset to be taken according to the underlying page and page
* size.
*
* Returns the offset to be taken according to the underlying page and page size.
*
* @return the offset to be taken
*/
int getOffset();
/**
* Returns the sorting parameters.
*
*
* @return
*/
Sort getSort();

View File

@@ -17,10 +17,9 @@ package org.springframework.data.domain;
import java.io.Serializable;
/**
* Simple interface for entities.
*
*
* @param <ID> the type of the identifier
* @author Oliver Gierke
*/
@@ -28,15 +27,14 @@ public interface Persistable<ID extends Serializable> extends Serializable {
/**
* Returns the id of the entity.
*
*
* @return the id
*/
ID getId();
/**
* Returns if the {@code Persistable} is new or was persisted already.
*
*
* @return if the object is new
*/
boolean isNew();

View File

@@ -342,7 +342,7 @@ public class Sort implements Iterable<org.springframework.data.domain.Sort.Order
return this.direction.equals(that.direction) && this.property.equals(that.property);
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()

View File

@@ -16,7 +16,6 @@
package org.springframework.data.mapping;
/**
* Value object to capture {@link Association}s.
*

View File

@@ -16,8 +16,6 @@
package org.springframework.data.mapping;
/**
* Callback interface to implement functionality to be applied to a collection of {@link Association}s.
*
@@ -25,7 +23,7 @@ package org.springframework.data.mapping;
* @author Oliver Gierke
*/
public interface AssociationHandler<P extends PersistentProperty<P>> {
/**
* Processes the given {@link Association}.
*

View File

@@ -18,14 +18,14 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
/**
* The name of the property
*
*
* @return The property name
*/
String getName();
/**
* The type of the property
*
*
* @return The property type
*/
Class<?> getType();
@@ -55,7 +55,7 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
/**
* Returns whether the property has to be regarded as entity which means its type will be also be considered to be a
* {@link PersistentEntity}.
*
*
* @return
*/
boolean isEntity();
@@ -63,21 +63,21 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
/**
* Returns the component type of the type if it is a {@link Collection}. Will return the type of the key if the
* property is a {@link Map}.
*
*
* @return the component type, the map's key type or {@literal null} if neither {@link Collection} nor {@link Map}.
*/
Class<?> getComponentType();
/**
* Returns the raw type as it's pulled from from the reflected property.
*
*
* @return the raw type of the property.
*/
Class<?> getRawType();
/**
* Returns the type of the values if the property is a {@link Map}.
*
*
* @return the map's value type or {@literal null} if no {@link Map}
*/
Class<?> getMapValueType();

View File

@@ -44,10 +44,10 @@ public class PreferredConstructor<T> {
* @param parameters
*/
public PreferredConstructor(Constructor<T> constructor, Parameter<?>... parameters) {
Assert.notNull(constructor);
Assert.notNull(parameters);
ReflectionUtils.makeAccessible(constructor);
this.constructor = constructor;
this.parameters = Arrays.asList(parameters);
@@ -70,7 +70,7 @@ public class PreferredConstructor<T> {
public Iterable<Parameter<?>> getParameters() {
return parameters;
}
/**
* Returns whether the constructor has {@link Parameter}s.
*
@@ -103,8 +103,7 @@ public class PreferredConstructor<T> {
/**
* Value object to represent constructor parameters.
*
* @param <T>
* the type of the paramter
* @param <T> the type of the paramter
* @author Oliver Gierke
*/
public static class Parameter<T> {

View File

@@ -16,9 +16,9 @@
package org.springframework.data.mapping;
/**
* Callback interface to do something with all plain {@link PersistentProperty}
* instances <em>except</em> associations and transient properties.
*
* Callback interface to do something with all plain {@link PersistentProperty} instances <em>except</em> associations
* and transient properties.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public interface PropertyHandler<P extends PersistentProperty<P>> {

View File

@@ -23,16 +23,22 @@ import org.springframework.data.util.TypeInformation;
import org.springframework.validation.Validator;
/**
* <p>This interface defines the overall context including all known
* PersistentEntity instances and methods to obtain instances on demand</p>
* <p>
* This interface defines the overall context including all known PersistentEntity instances and methods to obtain
* instances on demand
* </p>
* <p/>
* <p>This interface is used internally to establish associations
* between entities and also at runtime to obtain entities by name</p>
* <p>
* This interface is used internally to establish associations between entities and also at runtime to obtain entities
* by name
* </p>
* <p/>
* <p>The generic type parameters T & R are used to specify the
* mapped form of a class (example Table) and property (example Column) respectively.</p>
* <p>
* The generic type parameters T & R are used to specify the mapped form of a class (example Table) and property
* (example Column) respectively.
* </p>
* <p/>
*
*
* @author Graeme Rocher
* @author Jon Brisbin
* @author Oliver Gierke
@@ -41,7 +47,7 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
/**
* Returns all {@link PersistentEntity}s held in the context.
*
*
* @return
*/
Collection<E> getPersistentEntities();
@@ -56,7 +62,7 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
/**
* Returns a {@link PersistentEntity} for the given {@link TypeInformation}.
*
*
* @param type
* @return
*/
@@ -66,7 +72,7 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
* Returns all {@link PersistentProperty}s for the given path expression based on the given root {@link Class}. Path
* expression are dot separated, e.g. {@code person.firstname}.
*
* @param <T>
* @param <T>
* @param type
* @param path
* @return
@@ -74,9 +80,8 @@ public interface MappingContext<E extends PersistentEntity<?, P>, P extends Pers
<T> Iterable<P> getPersistentPropertyPath(Class<T> type, String path);
/**
* Obtains a validator for the given entity
* TODO: Why do we need validators at the {@link MappingContext}?
*
* Obtains a validator for the given entity TODO: Why do we need validators at the {@link MappingContext}?
*
* @param entity The entity
* @return A validator or null if none exists for the given entity
*/

View File

@@ -16,17 +16,16 @@
package org.springframework.data.mapping.context;
/**
* An interface to make beans aware of the active MappingContext in the current ApplicationContext.
*
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public interface MappingContextAware {
/**
* The active MappingContext for the environment.
*
*
* @param mappingContext
*/
void setMappingContext(MappingContext<?, ?> mappingContext);

View File

@@ -27,7 +27,7 @@ import org.springframework.context.ApplicationContextAware;
* BeanPostProcessor to make Spring beans aware of the current MappingContext. If a MappingContext exists with the
* default bean name ("mappingContext"), then that bean is used. If there is no MappingContext registered under the
* default bean name, then the first MappingContext it finds is the one it chooses.
*
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class MappingContextAwareBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

View File

@@ -24,7 +24,8 @@ import org.springframework.data.util.TypeInformation;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class MappingContextEvent<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> extends ApplicationEvent {
public class MappingContextEvent<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> extends
ApplicationEvent {
private static final long serialVersionUID = 1336466833846092490L;
private TypeInformation<?> typeInformation;

View File

@@ -32,7 +32,7 @@ import org.springframework.util.Assert;
/**
* Simple impementation of {@link PersistentProperty}.
*
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/

View File

@@ -28,24 +28,25 @@ import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
/**
* Special {@link PersistentProperty} that takes annotations at a property into account.
*
*
* @author Oliver Gierke
*/
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>> extends AbstractPersistentProperty<P> {
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>> extends
AbstractPersistentProperty<P> {
private final Value value;
/**
* Creates a new {@link AnnotationBasedPersistentProperty}.
*
*
* @param field
* @param propertyDescriptor
* @param owner
*/
public AnnotationBasedPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
public AnnotationBasedPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
PersistentEntity<?, P> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
this.value = field.getAnnotation(Value.class);
@@ -55,7 +56,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
/**
* Inspects a potentially available {@link Value} annotation at the property and returns the {@link String} value of
* it.
*
*
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#getSpelExpression()
*/
public String getSpelExpression() {
@@ -65,7 +66,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
/**
* Considers plain transient fields, fields annotated with {@link Transient}, {@link Value} or {@link Autowired} as
* transien.
*
*
* @see org.springframework.data.mapping.BasicPersistentProperty#isTransient()
*/
public boolean isTransient() {

View File

@@ -31,7 +31,7 @@ import org.springframework.util.Assert;
/**
* Simple value object to capture information of {@link PersistentEntity}s.
*
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
@@ -41,19 +41,18 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
private final TypeInformation<T> information;
private final Set<P> properties;
private final Set<Association<P>> associations;
private P idProperty;
private P idProperty;
/**
* Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}.
*
*
* @param information must not be {@literal null}.
*/
public BasicPersistentEntity(TypeInformation<T> information) {
this(information, null);
}
/**
* Creates a new {@link BasicPersistentEntity} for the given {@link TypeInformation} and {@link Comparator}. The given
* {@link Comparator} will be used to define the order of the {@link PersistentProperty} instances added to the
@@ -124,13 +123,13 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
*/
public P getPersistentProperty(String name) {
for (P property : properties) {
if (property.getName().equals(name)) {
return property;
}
}
return null;
}
@@ -180,16 +179,17 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
public void verify() {
}
/**
* Simple {@link Comparator} adaptor to delegate ordering to the inverse properties of the association.
*
* @author Oliver Gierke
*/
private static final class AssociationComparator<P extends PersistentProperty<P>> implements Comparator<Association<P>> {
private static final class AssociationComparator<P extends PersistentProperty<P>> implements
Comparator<Association<P>> {
private final Comparator<P> delegate;
public AssociationComparator(Comparator<P> delegate) {
Assert.notNull(delegate);
this.delegate = delegate;

View File

@@ -173,8 +173,7 @@ public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
public Object getProperty(PersistentProperty<?> property)
throws IllegalAccessException, InvocationTargetException {
public Object getProperty(PersistentProperty<?> property) throws IllegalAccessException, InvocationTargetException {
return getProperty(property, property.getType(), false);
}
@@ -201,7 +200,7 @@ public class BeanWrapper<E extends PersistentEntity<T, ?>, T> {
ReflectionUtils.makeAccessible(getter);
obj = ReflectionUtils.invokeMethod(getter, bean);
}
return getPotentiallyConvertedValue(obj, type);
}

View File

@@ -16,7 +16,7 @@ package org.springframework.data.mapping.model;
/**
* Thrown when an error occurs reading the mapping between object and datastore
*
*
* @author Graeme Rocher
* @since 1.0
*/

View File

@@ -19,41 +19,37 @@ import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
/**
* Interface capturing mutator methods for {@link PersistentEntity}s.
*
*
* @author Oliver Gierke
*/
public interface MutablePersistentEntity<T, P extends PersistentProperty<P>>
extends PersistentEntity<T, P> {
public interface MutablePersistentEntity<T, P extends PersistentProperty<P>> extends PersistentEntity<T, P> {
/**
* Sets the id property for the entity.
*
*
* @param property
*/
void setIdProperty(P property);
/**
* Adds a {@link PersistentProperty} to the entity.
*
*
* @param property
*/
void addPersistentProperty(P property);
/**
* Adds an {@link Association} to the entity.
*
*
* @param association
*/
void addAssociation(Association<P> association);
/**
* Callback method to trigger validation of the {@link PersistentEntity}. As
* {@link MutablePersistentEntity} is not immutable there might be some
* verification steps necessary after the object has reached is final state.
* Callback method to trigger validation of the {@link PersistentEntity}. As {@link MutablePersistentEntity} is not
* immutable there might be some verification steps necessary after the object has reached is final state.
*/
void verify();
}

View File

@@ -20,7 +20,7 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter;
/**
* Callback interface to lookup values for a given {@link Parameter}.
*
*
* @author Oliver Gierke
*/
public interface ParameterValueProvider {

View File

@@ -26,16 +26,14 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
/**
* Helper class to find a {@link PreferredConstructor}.
*
*
* @author Oliver Gierke
*/
public class PreferredConstructorDiscoverer<T> {
private final ParameterNameDiscoverer nameDiscoverer =
new LocalVariableTableParameterNameDiscoverer();
private final ParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private PreferredConstructor<T> constructor;
@@ -45,7 +43,7 @@ public class PreferredConstructorDiscoverer<T> {
/**
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
*
*
* @param owningType
*/
protected PreferredConstructorDiscoverer(TypeInformation<T> owningType) {
@@ -56,8 +54,7 @@ public class PreferredConstructorDiscoverer<T> {
for (Constructor<?> constructor : rawOwningType.getDeclaredConstructors()) {
PreferredConstructor<T> preferredConstructor =
buildPreferredConstructor(constructor, owningType);
PreferredConstructor<T> preferredConstructor = buildPreferredConstructor(constructor, owningType);
// Explicitly defined constructor trumps all
if (preferredConstructor.isExplicitlyAnnotated()) {
@@ -82,10 +79,9 @@ public class PreferredConstructorDiscoverer<T> {
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private PreferredConstructor<T> buildPreferredConstructor(
Constructor<?> constructor, TypeInformation<T> typeInformation) {
@SuppressWarnings({ "unchecked", "rawtypes" })
private PreferredConstructor<T> buildPreferredConstructor(Constructor<?> constructor,
TypeInformation<T> typeInformation) {
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
@@ -106,11 +102,9 @@ public class PreferredConstructorDiscoverer<T> {
parameters[i] = new Parameter(name, type, annotations);
}
return new PreferredConstructor<T>((Constructor<T>) constructor,
parameters);
return new PreferredConstructor<T>((Constructor<T>) constructor, parameters);
}
public PreferredConstructor<T> getConstructor() {
return constructor;
}

View File

@@ -25,11 +25,11 @@ import org.springframework.util.Assert;
/**
* Simple container to hold a set of types to be considered simple types.
*
*
* @author Oliver Gierke
*/
public class SimpleTypeHolder {
private static final Set<Class<?>> DEFAULTS = new HashSet<Class<?>>();
static {
@@ -63,11 +63,11 @@ public class SimpleTypeHolder {
DEFAULTS.add(Class.class);
DEFAULTS.add(Number.class);
}
private final Set<Class<?>> simpleTypes;
/**
* Creates a new {@link SimpleTypeHolder} containing the default types.
* Creates a new {@link SimpleTypeHolder} containing the default types.
*
* @see #SimpleTypeHolder(Set, boolean)
*/
@@ -84,10 +84,10 @@ public class SimpleTypeHolder {
* @param registerDefaults
*/
public SimpleTypeHolder(Set<? extends Class<?>> customSimpleTypes, boolean registerDefaults) {
Assert.notNull(customSimpleTypes);
this.simpleTypes = new HashSet<Class<?>>(customSimpleTypes);
if (registerDefaults) {
this.simpleTypes.addAll(DEFAULTS);
}
@@ -100,14 +100,14 @@ public class SimpleTypeHolder {
* @param source must not be {@literal null}
*/
public SimpleTypeHolder(Set<? extends Class<?>> customSimpleTypes, SimpleTypeHolder source) {
Assert.notNull(customSimpleTypes);
Assert.notNull(source);
this.simpleTypes = new HashSet<Class<?>>(customSimpleTypes);
this.simpleTypes.addAll(source.simpleTypes);
}
/**
* Returns whether the given type is considered a simple one.
*
@@ -118,7 +118,7 @@ public class SimpleTypeHolder {
Assert.notNull(type);
if (Object.class.equals(type)) {
return true;
}
}
for (Class<?> clazz : simpleTypes) {
if (type == clazz || clazz.isAssignableFrom(type)) {
return true;

View File

@@ -28,12 +28,13 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
*/
public class SpELAwareParameterValueProvider implements ParameterValueProvider {
private final SpelExpressionParser parser;
private final EvaluationContext context;
/**
* Creates a new {@link SpELAwareParameterValueProvider} from the given {@link SpelExpressionParser} and {@link EvaluationContext}.
* Creates a new {@link SpELAwareParameterValueProvider} from the given {@link SpelExpressionParser} and
* {@link EvaluationContext}.
*
* @param parser must not be {@literal null}
* @param context must not be {@literal null}

View File

@@ -11,12 +11,12 @@ import org.springframework.util.ClassUtils;
import sun.reflect.ReflectionFactory;
/**
* Try for a constructor taking state: failing that, try a no-arg
* constructor and then setUnderlyingNode().
*
* Try for a constructor taking state: failing that, try a no-arg constructor and then setUnderlyingNode().
*
* @author Rod Johnson
*/
public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, STATE> implements EntityInstantiator<BACKING_INTERFACE, STATE> {
public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, STATE> implements
EntityInstantiator<BACKING_INTERFACE, STATE> {
private final Log log = LogFactory.getLog(getClass());
private final Map<Class<? extends BACKING_INTERFACE>, StateBackedCreator<? extends BACKING_INTERFACE, STATE>> cache = new HashMap<Class<? extends BACKING_INTERFACE>, StateBackedCreator<? extends BACKING_INTERFACE, STATE>>();
@@ -24,10 +24,12 @@ public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, S
public <T extends BACKING_INTERFACE> T createEntityFromState(STATE n, Class<T> c) {
try {
StateBackedCreator<T, STATE> creator = (StateBackedCreator<T, STATE>) cache.get(c);
if (creator != null) return creator.create(n, c);
if (creator != null)
return creator.create(n, c);
synchronized (cache) {
creator = (StateBackedCreator<T, STATE>) cache.get(c);
if (creator != null) return creator.create(n, c);
if (creator != null)
return creator.create(n, c);
Class<STATE> stateClass = (Class<STATE>) n.getClass();
creator = createInstantiator(c, stateClass);
cache.put(c, creator);
@@ -42,20 +44,24 @@ public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, S
}
}
public void setInstantiators(Map<Class<? extends BACKING_INTERFACE>, StateBackedCreator<? extends BACKING_INTERFACE, STATE>> instantiators) {
public void setInstantiators(
Map<Class<? extends BACKING_INTERFACE>, StateBackedCreator<? extends BACKING_INTERFACE, STATE>> instantiators) {
this.cache.putAll(instantiators);
}
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> createInstantiator(Class<T> type, final Class<STATE> stateType) {
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> createInstantiator(Class<T> type,
final Class<STATE> stateType) {
StateBackedCreator<T, STATE> creator = stateTakingConstructorInstantiator(type, stateType);
if (creator != null) return creator;
if (creator != null)
return creator;
creator = emptyConstructorStateSettingInstantiator(type, stateType);
if (creator != null) return creator;
if (creator != null)
return creator;
return createFailingInstantiator(stateType);
}
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> createFailingInstantiator(final Class<STATE> stateType) {
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> createFailingInstantiator(
final Class<STATE> stateType) {
return new StateBackedCreator<T, STATE>() {
public T create(STATE n, Class<T> c) throws Exception {
throw new IllegalArgumentException(getFailingMessageForClass(c, stateType));
@@ -64,13 +70,15 @@ public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, S
}
protected String getFailingMessageForClass(Class<?> entityClass, Class<STATE> stateClass) {
return getClass().getSimpleName() + ": entity " + entityClass +
" must have either a constructor taking [" + stateClass + "] or a no-arg constructor and state setter.";
return getClass().getSimpleName() + ": entity " + entityClass + " must have either a constructor taking ["
+ stateClass + "] or a no-arg constructor and state setter.";
}
private <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> emptyConstructorStateSettingInstantiator(Class<T> type, Class<STATE> stateType) {
private <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> emptyConstructorStateSettingInstantiator(
Class<T> type, Class<STATE> stateType) {
final Constructor<T> constructor = getNoArgConstructor(type);
if (constructor == null) return null;
if (constructor == null)
return null;
log.info("Using " + type + " no-arg constructor");
@@ -88,7 +96,8 @@ public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, S
};
}
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> createWithoutConstructorInvocation(final Class<T> type, Class<STATE> stateType) {
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> createWithoutConstructorInvocation(
final Class<T> type, Class<STATE> stateType) {
ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
Constructor<?> objectConstructor = getDeclaredConstructor(Object.class);
final Constructor<?> serializationConstructor = rf.newConstructorForSerialization(type, objectConstructor);
@@ -101,17 +110,19 @@ public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, S
};
}
protected <T extends BACKING_INTERFACE> Constructor<T> getNoArgConstructor(Class<T> type) {
Constructor<T> constructor = ClassUtils.getConstructorIfAvailable(type);
if (constructor != null) return constructor;
if (constructor != null)
return constructor;
return getDeclaredConstructor(type);
}
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> stateTakingConstructorInstantiator(Class<T> type, Class<STATE> stateType) {
protected <T extends BACKING_INTERFACE> StateBackedCreator<T, STATE> stateTakingConstructorInstantiator(
Class<T> type, Class<STATE> stateType) {
Class<? extends STATE> stateInterface = (Class<? extends STATE>) stateType.getInterfaces()[0];
final Constructor<T> constructor = ClassUtils.getConstructorIfAvailable(type, stateInterface);
if (constructor == null) return null;
if (constructor == null)
return null;
log.info("Using " + type + " constructor taking " + stateInterface);
return new StateBackedCreator<T, STATE>() {
@@ -133,7 +144,7 @@ public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, S
/**
* Subclasses must implement to set state
*
*
* @param entity
* @param s
*/

View File

@@ -6,7 +6,7 @@ import org.springframework.core.convert.ConversionService;
/**
* Interface representing the set of changes in an entity.
*
*
* @author Rod Johnson
* @author Thomas Risberg
*/

View File

@@ -1,9 +1,8 @@
package org.springframework.data.persistence;
/**
* Interface introduced to objects exposing ChangeSet information
*
*
* @author Rod Johnson
* @author Thomas Risberg
*/

View File

@@ -18,10 +18,8 @@ public class ChangeSetConfiguration<T> {
return changeSetManager;
}
public void setChangeSetManager(
ChangeSetSynchronizer<ChangeSetBacked> changeSetManager) {
public void setChangeSetManager(ChangeSetSynchronizer<ChangeSetBacked> changeSetManager) {
this.changeSetManager = changeSetManager;
}
}

View File

@@ -3,9 +3,8 @@ package org.springframework.data.persistence;
import org.springframework.dao.DataAccessException;
/**
* Interface to be implemented by classes that can synchronize
* between data stores and ChangeSets.
*
* Interface to be implemented by classes that can synchronize between data stores and ChangeSets.
*
* @param <K> entity key
* @author Rod Johnson
*/
@@ -18,11 +17,12 @@ public interface ChangeSetPersister<K> {
/**
* TODO how to tell when not found? throw exception?
*/
void getPersistentState(Class<? extends ChangeSetBacked> entityClass, K key, ChangeSet changeSet) throws DataAccessException, NotFoundException;
void getPersistentState(Class<? extends ChangeSetBacked> entityClass, K key, ChangeSet changeSet)
throws DataAccessException, NotFoundException;
/**
* Return id
*
*
* @param entity
* @param cs
* @return
@@ -32,17 +32,16 @@ public interface ChangeSetPersister<K> {
/**
* Return key
*
*
* @param entity
* @param cs Key may be null if not persistent
* @param cs Key may be null if not persistent
* @return
* @throws DataAccessException
*/
K persistState(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException;
/**
* Exception thrown in alternate control flow if getPersistentState
* finds no entity data.
* Exception thrown in alternate control flow if getPersistentState finds no entity data.
*/
class NotFoundException extends Exception {

View File

@@ -5,9 +5,8 @@ import java.util.Map;
import org.springframework.dao.DataAccessException;
/**
* Interface to be implemented by classes that can synchronize
* between entities and ChangeSets.
*
* Interface to be implemented by classes that can synchronize between entities and ChangeSets.
*
* @param <E>
* @author Rod Johnson
*/
@@ -17,7 +16,7 @@ public interface ChangeSetSynchronizer<E extends ChangeSetBacked> {
/**
* Take all entity fields into a changeSet.
*
*
* @param entity
* @return
* @throws DataAccessException

View File

@@ -1,12 +1,9 @@
package org.springframework.data.persistence;
/**
* Interface to be implemented by classes that can instantiate and
* configure entities.
* The framework must do this when creating objects resulting from finders,
* even when there may be no no-arg constructor supplied by the user.
*
* Interface to be implemented by classes that can instantiate and configure entities. The framework must do this when
* creating objects resulting from finders, even when there may be no no-arg constructor supplied by the user.
*
* @author Rod Johnson
*/
public interface EntityInstantiator<BACKING_INTERFACE, STATE> {

View File

@@ -8,7 +8,7 @@ import org.springframework.core.convert.ConversionService;
/**
* Simple ChangeSet implementation backed by a HashMap.
*
*
* @author Thomas Risberg
* @author Rod Johnson
*/

View File

@@ -3,8 +3,8 @@ package org.springframework.data.persistence;
/**
* encapsulates the instantiator of state-backed classes and populating them with the provided state.
* <p/>
* Can be implemented and registered with the concrete AbstractConstructorEntityInstantiator to provide
* non reflection bases instantiaton for domain classes
* Can be implemented and registered with the concrete AbstractConstructorEntityInstantiator to provide non reflection
* bases instantiaton for domain classes
*/
public interface StateBackedCreator<T, STATE> {
T create(STATE n, Class<T> c) throws Exception;

View File

@@ -12,7 +12,8 @@ public abstract class StateProvider {
public static <STATE> void setUnderlyingState(STATE state) {
if (stateHolder.get() != null)
throw new IllegalStateException("StateHolder already contains state " + stateHolder.get() + " in thread " + Thread.currentThread());
throw new IllegalStateException("StateHolder already contains state " + stateHolder.get() + " in thread "
+ Thread.currentThread());
stateHolder.set(state);
}

View File

@@ -19,7 +19,7 @@ import com.mysema.query.types.EntityPath;
/**
* Strategy interface to abstract the ways to translate an plain domain class into a {@link EntityPath}.
*
*
* @author Oliver Gierke
*/
public interface EntityPathResolver {

View File

@@ -21,7 +21,6 @@ import org.springframework.data.domain.Pageable;
import com.mysema.query.types.OrderSpecifier;
import com.mysema.query.types.Predicate;
/**
* Interface to allow execution of QueryDsl {@link Predicate} instances.
*
@@ -29,51 +28,45 @@ import com.mysema.query.types.Predicate;
*/
public interface QueryDslPredicateExecutor<T> {
/**
* Returns a single entity matching the given {@link Predicate}.
*
* @param spec
* @return
*/
T findOne(Predicate predicate);
/**
* Returns a single entity matching the given {@link Predicate}.
*
* @param spec
* @return
*/
T findOne(Predicate predicate);
/**
* Returns all entities matching the given {@link Predicate}.
*
* @param spec
* @return
*/
Iterable<T> findAll(Predicate predicate);
/**
* Returns all entities matching the given {@link Predicate}.
*
* @param spec
* @return
*/
Iterable<T> findAll(Predicate predicate);
/**
* Returns all entities matching the given {@link Predicate} applying the given {@link OrderSpecifier}s.
*
* @param predicate
* @param orders
* @return
*/
Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);
/**
* Returns a {@link Page} of entities matching the given {@link Predicate}.
*
* @param predicate
* @param pageable
* @return
*/
Page<T> findAll(Predicate predicate, Pageable pageable);
/**
* Returns all entities matching the given {@link Predicate} applying the
* given {@link OrderSpecifier}s.
*
* @param predicate
* @param orders
* @return
*/
Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);
/**
* Returns a {@link Page} of entities matching the given {@link Predicate}.
*
* @param predicate
* @param pageable
* @return
*/
Page<T> findAll(Predicate predicate, Pageable pageable);
/**
* Returns the number of instances that the given {@link Predicate} will
* return.
*
* @param predicate the {@link Predicate} to count instances for
* @return the number of instances
*/
long count(Predicate predicate);
/**
* Returns the number of instances that the given {@link Predicate} will return.
*
* @param predicate the {@link Predicate} to count instances for
* @return the number of instances
*/
long count(Predicate predicate);
}

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.data.querydsl;
/**
* @author Oliver Gierke
*/

View File

@@ -23,27 +23,23 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* Simple implementation of {@link EntityPathResolver} to lookup a query
* class by reflection and using the static field of the same type.
*
* Simple implementation of {@link EntityPathResolver} to lookup a query class by reflection and using the static field
* of the same type.
*
* @author Oliver Gierke
*/
public enum SimpleEntityPathResolver implements EntityPathResolver {
INSTANCE;
private static final String NO_CLASS_FOUND_TEMPLATE =
"Did not find a query class %s for domain class %s!";
private static final String NO_FIELD_FOUND_TEMPLATE =
"Did not find a static field of the same type in %s!";
private static final String NO_CLASS_FOUND_TEMPLATE = "Did not find a query class %s for domain class %s!";
private static final String NO_FIELD_FOUND_TEMPLATE = "Did not find a static field of the same type in %s!";
/**
* Creates an {@link EntityPath} instance for the given domain class.
* Tries to lookup a class matching the naming convention (prepend Q to
* the simple name of the class, same package) and find a static field
* of the same type in it.
*
* Creates an {@link EntityPath} instance for the given domain class. Tries to lookup a class matching the naming
* convention (prepend Q to the simple name of the class, same package) and find a static field of the same type in
* it.
*
* @param domainClass
* @return
*/
@@ -53,31 +49,24 @@ public enum SimpleEntityPathResolver implements EntityPathResolver {
String pathClassName = getQueryClassName(domainClass);
try {
Class<?> pathClass =
ClassUtils.forName(pathClassName,
SimpleEntityPathResolver.class.getClassLoader());
Class<?> pathClass = ClassUtils.forName(pathClassName, SimpleEntityPathResolver.class.getClassLoader());
Field field = getStaticFieldOfType(pathClass);
if (field == null) {
throw new IllegalStateException(String.format(
NO_FIELD_FOUND_TEMPLATE, pathClass));
throw new IllegalStateException(String.format(NO_FIELD_FOUND_TEMPLATE, pathClass));
} else {
return (EntityPath<T>) ReflectionUtils
.getField(field, null);
return (EntityPath<T>) ReflectionUtils.getField(field, null);
}
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(String.format(
NO_CLASS_FOUND_TEMPLATE, pathClassName,
domainClass.getName()), e);
throw new IllegalArgumentException(String.format(NO_CLASS_FOUND_TEMPLATE, pathClassName, domainClass.getName()),
e);
}
}
/**
* Returns the first static field of the given type inside the given
* type.
*
* Returns the first static field of the given type inside the given type.
*
* @param type
* @return
*/
@@ -94,30 +83,25 @@ public enum SimpleEntityPathResolver implements EntityPathResolver {
}
Class<?> superclass = type.getSuperclass();
return Object.class.equals(superclass) ? null
: getStaticFieldOfType(superclass);
return Object.class.equals(superclass) ? null : getStaticFieldOfType(superclass);
}
/**
* Returns the name of the query class for the given domain class.
*
*
* @param domainClass
* @return
*/
private String getQueryClassName(Class<?> domainClass) {
String simpleClassName = ClassUtils.getShortName(domainClass);
return String.format("%s.Q%s%s",
domainClass.getPackage().getName(),
getClassBase(simpleClassName), domainClass.getSimpleName());
return String.format("%s.Q%s%s", domainClass.getPackage().getName(), getClassBase(simpleClassName),
domainClass.getSimpleName());
}
/**
* Analyzes the short class name and potentially returns the outer
* class.
*
* Analyzes the short class name and potentially returns the outer class.
*
* @param shortName
* @return
*/

View File

@@ -17,10 +17,9 @@ package org.springframework.data.repository;
import java.io.Serializable;
/**
* Interface for generic CRUD operations on a repository for a specific type.
*
*
* @author Oliver Gierke
* @author Eberhard Wolff
*/
@@ -28,61 +27,54 @@ import java.io.Serializable;
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
/**
* Saves a given entity. Use the returned instance for further operations as
* the save operation might have changed the entity instance completely.
*
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity
* @return the saved entity
*/
T save(T entity);
/**
* Saves all given entities.
*
*
* @param entities
* @return
*/
Iterable<T> save(Iterable<? extends T> entities);
/**
* Retrives an entity by its primary key.
*
*
* @param id
* @return the entity with the given primary key or {@code null} if none
* found
* @return the entity with the given primary key or {@code null} if none found
* @throws IllegalArgumentException if primaryKey is {@code null}
*/
T findOne(ID id);
/**
* Returns whether an entity with the given id exists.
*
*
* @param id
* @return true if an entity with the given id exists, alse otherwise
* @throws IllegalArgumentException if primaryKey is {@code null}
*/
boolean exists(ID id);
/**
* Returns all instances of the type.
*
*
* @return all entities
*/
Iterable<T> findAll();
/**
* Returns the number of entities available.
*
*
* @return the number of entities
*/
long count();
/**
* Deletes the entity with the given id.
*
@@ -90,23 +82,20 @@ public interface CrudRepository<T, ID extends Serializable> extends Repository<T
*/
void delete(ID id);
/**
* Deletes a given entity.
*
*
* @param entity
*/
void delete(T entity);
/**
* Deletes the given entities.
*
*
* @param entities
*/
void delete(Iterable<? extends T> entities);
/**
* Deletes all entities managed by the repository.
*/

View File

@@ -21,17 +21,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to exclude repository interfaces from being picked up and thus in
* consequence getting an instance being created.
* Annotation to exclude repository interfaces from being picked up and thus in consequence getting an instance being
* created.
* <p/>
* This will typically be used when providing an extended base interface for all
* repositories in combination with a custom repository base class to implement
* methods declared in that intermediate interface. In this case you typically
* derive your concrete repository interfaces from the intermediate one but
* don't want to create a Spring bean for the intermediate interface.
*
* This will typically be used when providing an extended base interface for all repositories in combination with a
* custom repository base class to implement methods declared in that intermediate interface. In this case you typically
* derive your concrete repository interfaces from the intermediate one but don't want to create a Spring bean for the
* intermediate interface.
*
* @author Oliver Gierke
*/
@Retention(RetentionPolicy.RUNTIME)

View File

@@ -21,33 +21,29 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
/**
* Extension of {@link CrudRepository} to provide additional methods to retrieve
* entities using the pagination and sorting abstraction.
*
* Extension of {@link CrudRepository} to provide additional methods to retrieve entities using the pagination and
* sorting abstraction.
*
* @author Oliver Gierke
* @see Sort
* @see Pageable
* @see Page
*/
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends
CrudRepository<T, ID> {
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
/**
* Returns all entities sorted by the given options.
*
*
* @param sort
* @return all entities sorted by the given options
*/
Iterable<T> findAll(Sort sort);
/**
* Returns a {@link Page} of entities meeting the paging restriction
* provided in the {@code Pageable} object.
*
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
*
* @param pageable
* @return a page of entities
*/

View File

@@ -43,7 +43,7 @@ public @interface RepositoryDefinition {
* @return
*/
Class<?> domainClass();
/**
* The id class of the entity the repository manages. Equivalent to the ID type parameter in {@link Repository}.
*

View File

@@ -49,25 +49,19 @@ import org.springframework.data.repository.RepositoryDefinition;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Base class to implement repository namespaces. These will typically consist
* of a main XML element potentially having child elements. The parser will wrap
* the XML element into a {@link GlobalRepositoryConfigInformation} object and
* allow either manual configuration or automatic detection of repository
* interfaces.
*
* Base class to implement repository namespaces. These will typically consist of a main XML element potentially having
* child elements. The parser will wrap the XML element into a {@link GlobalRepositoryConfigInformation} object and
* allow either manual configuration or automatic detection of repository interfaces.
*
* @author Oliver Gierke
*/
public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalRepositoryConfigInformation<T>, T extends SingleRepositoryConfigInformation<S>>
implements BeanDefinitionParser {
private static final Log LOG = LogFactory.getLog(
AbstractRepositoryConfigDefinitionParser.class);
private static final String REPOSITORY_INTERFACE_POST_PROCESSOR =
"org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor";
private static final Log LOG = LogFactory.getLog(AbstractRepositoryConfigDefinitionParser.class);
private static final String REPOSITORY_INTERFACE_POST_PROCESSOR = "org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor";
/*
* (non-Javadoc)
@@ -97,11 +91,9 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
return null;
}
/**
* Executes repository auto configuration by scanning the provided base
* package for repository interfaces.
*
* Executes repository auto configuration by scanning the provided base package for repository interfaces.
*
* @param config
* @param parser
*/
@@ -109,36 +101,27 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
LOG.debug("Triggering auto repository detection");
ResourceLoader resourceLoader =
parser.getReaderContext().getResourceLoader();
ResourceLoader resourceLoader = parser.getReaderContext().getResourceLoader();
// Detect available repository interfaces
Set<String> repositoryInterfaces =
getRepositoryInterfacesForAutoConfig(config, resourceLoader,
parser.getReaderContext());
Set<String> repositoryInterfaces = getRepositoryInterfacesForAutoConfig(config, resourceLoader,
parser.getReaderContext());
for (String repositoryInterface : repositoryInterfaces) {
registerGenericRepositoryFactoryBean(
parser,
config.getAutoconfigRepositoryInformation(repositoryInterface));
registerGenericRepositoryFactoryBean(parser, config.getAutoconfigRepositoryInformation(repositoryInterface));
}
}
private Set<String> getRepositoryInterfacesForAutoConfig(S config, ResourceLoader loader, ReaderContext reader) {
private Set<String> getRepositoryInterfacesForAutoConfig(S config,
ResourceLoader loader, ReaderContext reader) {
ClassPathScanningCandidateComponentProvider scanner =
new RepositoryComponentProvider(
config.getRepositoryBaseInterface());
ClassPathScanningCandidateComponentProvider scanner = new RepositoryComponentProvider(
config.getRepositoryBaseInterface());
scanner.setResourceLoader(loader);
TypeFilterParser parser =
new TypeFilterParser(loader.getClassLoader(), reader);
TypeFilterParser parser = new TypeFilterParser(loader.getClassLoader(), reader);
parser.parseFilters(config.getSource(), scanner);
Set<BeanDefinition> findCandidateComponents =
scanner.findCandidateComponents(config.getBasePackage());
Set<BeanDefinition> findCandidateComponents = scanner.findCandidateComponents(config.getBasePackage());
Set<String> interfaceNames = new HashSet<String>();
for (BeanDefinition definition : findCandidateComponents) {
@@ -148,21 +131,17 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
return interfaceNames;
}
/**
* Returns a {@link GlobalRepositoryConfigInformation} implementation for
* the given element.
*
* Returns a {@link GlobalRepositoryConfigInformation} implementation for the given element.
*
* @param element
* @return
*/
protected abstract S getGlobalRepositoryConfigInformation(Element element);
/**
* Proceeds manual configuration by traversing the context's
* {@link SingleRepositoryConfigInformation}s.
*
* Proceeds manual configuration by traversing the context's {@link SingleRepositoryConfigInformation}s.
*
* @param context
* @param parser
*/
@@ -170,58 +149,47 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
LOG.debug("Triggering manual repository detection");
for (T repositoryContext : context
.getSingleRepositoryConfigInformations()) {
for (T repositoryContext : context.getSingleRepositoryConfigInformations()) {
registerGenericRepositoryFactoryBean(parser, repositoryContext);
}
}
private void handleError(Exception e, Element source, ReaderContext reader) {
reader.error(e.getMessage(), reader.extractSource(source), e.getCause());
}
/**
* Registers a generic repository factory bean for a bean with the given
* name and the provided configuration context.
*
* Registers a generic repository factory bean for a bean with the given name and the provided configuration context.
*
* @param parser
* @param name
* @param context
*/
private void registerGenericRepositoryFactoryBean(ParserContext parser,
T context) {
private void registerGenericRepositoryFactoryBean(ParserContext parser, T context) {
try {
Object beanSource = parser.extractSource(context.getSource());
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.rootBeanDefinition(context
.getRepositoryFactoryBeanClassName());
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(context
.getRepositoryFactoryBeanClassName());
builder.addPropertyValue("repositoryInterface",
context.getInterfaceName());
builder.addPropertyValue("queryLookupStrategyKey",
context.getQueryLookupStrategyKey());
builder.addPropertyValue("repositoryInterface", context.getInterfaceName());
builder.addPropertyValue("queryLookupStrategyKey", context.getQueryLookupStrategyKey());
builder.addPropertyValue("namedQueries",
new NamedQueriesBeanDefinitionParser(context.getNamedQueriesLocation()).parse(context.getSource(), parser));
String transactionManagerRef = context.getTransactionManagerRef();
if (StringUtils.hasText(transactionManagerRef)) {
builder.addPropertyValue("transactionManager",
transactionManagerRef);
builder.addPropertyValue("transactionManager", transactionManagerRef);
}
String customImplementationBeanName =
registerCustomImplementation(context, parser, beanSource);
String customImplementationBeanName = registerCustomImplementation(context, parser, beanSource);
if (customImplementationBeanName != null) {
builder.addPropertyReference("customImplementation",
customImplementationBeanName);
builder.addPropertyReference("customImplementation", customImplementationBeanName);
}
postProcessBeanDefinition(context, builder, parser.getRegistry(), beanSource);
@@ -230,50 +198,40 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
beanDefinition.setSource(beanSource);
if (LOG.isDebugEnabled()) {
LOG.debug(
"Registering repository: " + context.getBeanId() +
" - Interface: " + context.getInterfaceName() +
" - Factory: " + context.getRepositoryFactoryBeanClassName() +
", - Custom implementation: " + customImplementationBeanName);
LOG.debug("Registering repository: " + context.getBeanId() + " - Interface: " + context.getInterfaceName()
+ " - Factory: " + context.getRepositoryFactoryBeanClassName() + ", - Custom implementation: "
+ customImplementationBeanName);
}
BeanComponentDefinition definition =
new BeanComponentDefinition(beanDefinition,
context.getBeanId());
BeanComponentDefinition definition = new BeanComponentDefinition(beanDefinition, context.getBeanId());
parser.registerBeanComponent(definition);
} catch (RuntimeException e) {
handleError(e, context.getSource(), parser.getReaderContext());
}
}
/**
* Callback to post process a repository bean definition prior to actual
* registration.
*
* Callback to post process a repository bean definition prior to actual registration.
*
* @param context
* @param builder
* @param beanSource
*/
protected void postProcessBeanDefinition(T context,
BeanDefinitionBuilder builder, BeanDefinitionRegistry registry, Object beanSource) {
protected void postProcessBeanDefinition(T context, BeanDefinitionBuilder builder, BeanDefinitionRegistry registry,
Object beanSource) {
}
/**
* Registers a possibly available custom repository implementation on the
* repository bean. Tries to find an already registered bean to reference or
* tries to detect a custom implementation itself.
*
* Registers a possibly available custom repository implementation on the repository bean. Tries to find an already
* registered bean to reference or tries to detect a custom implementation itself.
*
* @param config
* @param parser
* @param source
* @return the bean name of the custom implementation or {@code null} if
* none available
* @return the bean name of the custom implementation or {@code null} if none available
*/
private String registerCustomImplementation(T config, ParserContext parser,
Object source) {
private String registerCustomImplementation(T config, ParserContext parser, Object source) {
String beanName = config.getImplementationBeanName();
@@ -285,22 +243,19 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
// Autodetect implementation
if (config.autodetectCustomImplementation()) {
AbstractBeanDefinition beanDefinition =
detectCustomImplementation(config, parser);
AbstractBeanDefinition beanDefinition = detectCustomImplementation(config, parser);
if (null == beanDefinition) {
return null;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Registering custom repository implementation: " +
config.getImplementationBeanName() + " " +
beanDefinition.getBeanClassName());
LOG.debug("Registering custom repository implementation: " + config.getImplementationBeanName() + " "
+ beanDefinition.getBeanClassName());
}
beanDefinition.setSource(source);
parser.registerBeanComponent(new BeanComponentDefinition(
beanDefinition, beanName));
parser.registerBeanComponent(new BeanComponentDefinition(beanDefinition, beanName));
} else {
beanName = config.getCustomImplementationRef();
@@ -309,89 +264,68 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
return beanName;
}
/**
* Tries to detect a custom implementation for a repository bean by
* classpath scanning.
*
* Tries to detect a custom implementation for a repository bean by classpath scanning.
*
* @param config
* @param parser
* @return the {@code AbstractBeanDefinition} of the custom implementation
* or {@literal null} if none found
* @return the {@code AbstractBeanDefinition} of the custom implementation or {@literal null} if none found
*/
private AbstractBeanDefinition detectCustomImplementation(T config,
ParserContext parser) {
private AbstractBeanDefinition detectCustomImplementation(T config, ParserContext parser) {
// Build pattern to lookup implementation class
Pattern pattern =
Pattern.compile(".*" + config.getImplementationClassName());
Pattern pattern = Pattern.compile(".*" + config.getImplementationClassName());
// Build classpath scanner and lookup bean definition
ClassPathScanningCandidateComponentProvider provider =
new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(parser.getReaderContext()
.getResourceLoader());
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.setResourceLoader(parser.getReaderContext().getResourceLoader());
provider.addIncludeFilter(new RegexPatternTypeFilter(pattern));
Set<BeanDefinition> definitions =
provider.findCandidateComponents(config.getBasePackage());
Set<BeanDefinition> definitions = provider.findCandidateComponents(config.getBasePackage());
return (0 == definitions.size() ? null
: (AbstractBeanDefinition) definitions.iterator().next());
return (0 == definitions.size() ? null : (AbstractBeanDefinition) definitions.iterator().next());
}
/**
* Callback to register additional bean definitions for a
* {@literal repositories} root node. This usually includes beans you have
* to set up once independently of the number of repositories to be created.
* Will be called before any repositories bean definitions have been
* registered.
*
* Callback to register additional bean definitions for a {@literal repositories} root node. This usually includes
* beans you have to set up once independently of the number of repositories to be created. Will be called before any
* repositories bean definitions have been registered.
*
* @param registry
* @param source
*/
protected void registerBeansForRoot(BeanDefinitionRegistry registry,
Object source) {
protected void registerBeansForRoot(BeanDefinitionRegistry registry, Object source) {
AbstractBeanDefinition definition =
BeanDefinitionBuilder.rootBeanDefinition(
REPOSITORY_INTERFACE_POST_PROCESSOR)
.getBeanDefinition();
AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(REPOSITORY_INTERFACE_POST_PROCESSOR)
.getBeanDefinition();
registerWithSourceAndGeneratedBeanName(registry, definition, source);
}
/**
* Returns whether the given {@link BeanDefinitionRegistry} already contains
* a bean of the given type assuming the bean name has been autogenerated.
*
* Returns whether the given {@link BeanDefinitionRegistry} already contains a bean of the given type assuming the
* bean name has been autogenerated.
*
* @param type
* @param registry
* @return
*/
protected static boolean hasBean(Class<?> type,
BeanDefinitionRegistry registry) {
protected static boolean hasBean(Class<?> type, BeanDefinitionRegistry registry) {
String name =
String.format("%s%s0", type.getName(),
GENERATED_BEAN_NAME_SEPARATOR);
String name = String.format("%s%s0", type.getName(), GENERATED_BEAN_NAME_SEPARATOR);
return registry.containsBeanDefinition(name);
}
/**
* Sets the given source on the given {@link AbstractBeanDefinition} and
* registers it inside the given {@link BeanDefinitionRegistry}.
*
* Sets the given source on the given {@link AbstractBeanDefinition} and registers it inside the given
* {@link BeanDefinitionRegistry}.
*
* @param registry
* @param bean
* @param source
* @return
*/
protected static String registerWithSourceAndGeneratedBeanName(
BeanDefinitionRegistry registry, AbstractBeanDefinition bean,
Object source) {
protected static String registerWithSourceAndGeneratedBeanName(BeanDefinitionRegistry registry,
AbstractBeanDefinition bean, Object source) {
bean.setSource(source);
@@ -402,18 +336,16 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
}
/**
* Custom {@link ClassPathScanningCandidateComponentProvider} scanning for
* interfaces extending the given base interface. Skips interfaces annotated
* with {@link NoRepositoryBean}.
*
* Custom {@link ClassPathScanningCandidateComponentProvider} scanning for interfaces extending the given base
* interface. Skips interfaces annotated with {@link NoRepositoryBean}.
*
* @author Oliver Gierke
*/
static class RepositoryComponentProvider extends
ClassPathScanningCandidateComponentProvider {
static class RepositoryComponentProvider extends ClassPathScanningCandidateComponentProvider {
/**
* Creates a new {@link RepositoryComponentProvider}.
*
*
* @param repositoryInterface the interface to scan for
*/
public RepositoryComponentProvider(Class<?> repositoryInterface) {
@@ -424,7 +356,6 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
addExcludeFilter(new AnnotationTypeFilter(NoRepositoryBean.class));
}
/*
* (non-Javadoc)
*
@@ -434,30 +365,25 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
* .beans.factory.annotation.AnnotatedBeanDefinition)
*/
@Override
protected boolean isCandidateComponent(
AnnotatedBeanDefinition beanDefinition) {
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
boolean isNonRepositoryInterface =
!isGenericRepositoryInterface(beanDefinition
.getBeanClassName());
boolean isTopLevelType =
!beanDefinition.getMetadata().hasEnclosingClass();
boolean isNonRepositoryInterface = !isGenericRepositoryInterface(beanDefinition.getBeanClassName());
boolean isTopLevelType = !beanDefinition.getMetadata().hasEnclosingClass();
return isNonRepositoryInterface && isTopLevelType;
}
/**
* {@link org.springframework.core.type.filter.TypeFilter} that only
* matches interfaces. Thus setting this up makes only sense providing
* an interface type as {@code targetType}.
*
* {@link org.springframework.core.type.filter.TypeFilter} that only matches interfaces. Thus setting this up makes
* only sense providing an interface type as {@code targetType}.
*
* @author Oliver Gierke
*/
private static class InterfaceTypeFilter extends AssignableTypeFilter {
/**
* Creates a new {@link InterfaceTypeFilter}.
*
*
* @param targetType
*/
public InterfaceTypeFilter(Class<?> targetType) {
@@ -465,7 +391,6 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
super(targetType);
}
/*
* (non-Javadoc)
*
@@ -475,23 +400,21 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
* org.springframework.core.type.classreading.MetadataReaderFactory)
*/
@Override
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory)
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
return metadataReader.getClassMetadata().isInterface()
&& super.match(metadataReader, metadataReaderFactory);
return metadataReader.getClassMetadata().isInterface() && super.match(metadataReader, metadataReaderFactory);
}
}
// Copy of Spring's AnnotationTypeFilter until SPR-8336 gets resolved.
/**
* A simple filter which matches classes with a given annotation,
* checking inherited annotations as well.
*
* <p>The matching logic mirrors that of <code>Class.isAnnotationPresent()</code>.
*
* A simple filter which matches classes with a given annotation, checking inherited annotations as well.
*
* <p>
* The matching logic mirrors that of <code>Class.isAnnotationPresent()</code>.
*
* @author Mark Fisher
* @author Ramnivas Laddad
* @author Juergen Hoeller
@@ -503,13 +426,11 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
private final boolean considerMetaAnnotations;
/**
* Create a new AnnotationTypeFilter for the given annotation type.
* This filter will also match meta-annotations. To disable the
* meta-annotation matching, use the constructor that accepts a
* '<code>considerMetaAnnotations</code>' argument. The filter will
* not match interfaces.
* Create a new AnnotationTypeFilter for the given annotation type. This filter will also match meta-annotations.
* To disable the meta-annotation matching, use the constructor that accepts a '
* <code>considerMetaAnnotations</code>' argument. The filter will not match interfaces.
*
* @param annotationType the annotation type to match
*/
public AnnotationTypeFilter(Class<? extends Annotation> annotationType) {
@@ -517,8 +438,8 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
}
/**
* Create a new AnnotationTypeFilter for the given annotation type.
* The filter will not match interfaces.
* Create a new AnnotationTypeFilter for the given annotation type. The filter will not match interfaces.
*
* @param annotationType the annotation type to match
* @param considerMetaAnnotations whether to also match on meta-annotations
*/
@@ -528,35 +449,34 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
/**
* Create a new {@link AnnotationTypeFilter} for the given annotation type.
*
* @param annotationType the annotation type to match
* @param considerMetaAnnotations whether to also match on meta-annotations
* @param considerInterfaces whether to also match interfaces
*/
public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) {
public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations,
boolean considerInterfaces) {
super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces);
this.annotationType = annotationType;
this.considerMetaAnnotations = considerMetaAnnotations;
}
@Override
protected boolean matchSelf(MetadataReader metadataReader) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
return metadata.hasAnnotation(this.annotationType.getName())
|| (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
@Override
protected Boolean matchSuperClass(String superClassName) {
if (Object.class.getName().equals(superClassName)) {
return Boolean.FALSE;
}
else if (superClassName.startsWith("java.")) {
} else if (superClassName.startsWith("java.")) {
try {
Class<?> clazz = getClass().getClassLoader().loadClass(superClassName);
return (clazz.getAnnotation(this.annotationType) != null);
}
catch (ClassNotFoundException ex) {
} catch (ClassNotFoundException ex) {
// Class not found - can't determine a match that way.
}
}

View File

@@ -20,24 +20,21 @@ import static org.springframework.util.StringUtils.*;
import org.springframework.util.Assert;
/**
* A {@link SingleRepositoryConfigInformation} implementation that is not backed
* by an XML element but by a scanned interface. As this is derived from the
* parent, most of the lookup logic is delegated to the parent as well.
*
* A {@link SingleRepositoryConfigInformation} implementation that is not backed by an XML element but by a scanned
* interface. As this is derived from the parent, most of the lookup logic is delegated to the parent as well.
*
* @author Oliver Gierke
*/
public class AutomaticRepositoryConfigInformation<S extends CommonRepositoryConfigInformation>
extends ParentDelegatingRepositoryConfigInformation<S> {
public class AutomaticRepositoryConfigInformation<S extends CommonRepositoryConfigInformation> extends
ParentDelegatingRepositoryConfigInformation<S> {
private final String interfaceName;
/**
* Creates a new {@link AutomaticRepositoryConfigInformation} for the given
* interface name and {@link CommonRepositoryConfigInformation} parent.
*
* Creates a new {@link AutomaticRepositoryConfigInformation} for the given interface name and
* {@link CommonRepositoryConfigInformation} parent.
*
* @param interfaceName
* @param parent
*/
@@ -48,7 +45,6 @@ public class AutomaticRepositoryConfigInformation<S extends CommonRepositoryConf
this.interfaceName = interfaceName;
}
/*
* (non-Javadoc)
*
@@ -61,7 +57,6 @@ public class AutomaticRepositoryConfigInformation<S extends CommonRepositoryConf
return uncapitalize(getShortName(interfaceName));
}
/*
* (non-Javadoc)
*

View File

@@ -19,60 +19,52 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.transaction.PlatformTransactionManager;
import org.w3c.dom.Element;
/**
* Interface for shared repository information.
*
*
* @author Oliver Gierke
*/
public interface CommonRepositoryConfigInformation {
/**
* Returns the element the repository information is derived from.
*
*
* @return
*/
Element getSource();
/**
* Returns the base package.
*
*
* @return
*/
String getBasePackage();
/**
* Returns the suffix to use for implementation bean lookup or class
* detection.
*
* Returns the suffix to use for implementation bean lookup or class detection.
*
* @return
*/
String getRepositoryImplementationSuffix();
/**
* Returns the configured repository factory class.
*
*
* @return
*/
String getRepositoryFactoryBeanClassName();
/**
* Returns the bean name of the {@link PlatformTransactionManager} to be
* used. Returns {@literal null} if no reference has been configured
* explicitly.
*
* Returns the bean name of the {@link PlatformTransactionManager} to be used. Returns {@literal null} if no reference
* has been configured explicitly.
*
* @return
*/
String getTransactionManagerRef();
/**
* Returns the strategy finder methods should be resolved.
*
*
* @return
*/
Key getQueryLookupStrategyKey();

View File

@@ -18,40 +18,36 @@ package org.springframework.data.repository.config;
/**
* @author Oliver Gierke
*/
public interface GlobalRepositoryConfigInformation<T extends SingleRepositoryConfigInformation<?>>
extends CommonRepositoryConfigInformation {
public interface GlobalRepositoryConfigInformation<T extends SingleRepositoryConfigInformation<?>> extends
CommonRepositoryConfigInformation {
/**
* Returns the
*
*
* @param interfaceName
* @return
*/
T getAutoconfigRepositoryInformation(String interfaceName);
/**
* Returns all {@link SingleRepositoryConfigInformation} instances used for
* manual configuration.
*
* Returns all {@link SingleRepositoryConfigInformation} instances used for manual configuration.
*
* @return
*/
Iterable<T> getSingleRepositoryConfigInformations();
/**
* Returns whether to consider manual configuration. If this returns true,
* clients should use {@link #getSingleRepositoryConfigInformations()} to
* lookup configuration information for individual repository beans.
*
* Returns whether to consider manual configuration. If this returns true, clients should use
* {@link #getSingleRepositoryConfigInformations()} to lookup configuration information for individual repository
* beans.
*
* @return
*/
boolean configureManually();
/**
* Returns the base interface to use
*
*
* @return
*/
Class<?> getRepositoryBaseInterface();

View File

@@ -20,20 +20,18 @@ import static org.springframework.util.StringUtils.*;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.w3c.dom.Element;
/**
* Configuration information for manual repository configuration.
*
*
* @author Oliver Gierke
*/
public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigInformation>
extends ParentDelegatingRepositoryConfigInformation<T> {
public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigInformation> extends
ParentDelegatingRepositoryConfigInformation<T> {
private static final String CUSTOM_IMPL_REF = "custom-impl-ref";
private Element element;
/**
* @param parent
*/
@@ -43,7 +41,6 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
this.element = element;
}
/*
* (non-Javadoc)
*
@@ -56,7 +53,6 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
return element.getAttribute("id");
}
/*
* (non-Javadoc)
*
@@ -69,7 +65,6 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
return getBasePackage() + "." + capitalize(getBeanId());
}
/*
* (non-Javadoc)
*
@@ -83,10 +78,9 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
return element.getAttribute(CUSTOM_IMPL_REF);
}
/**
* Returns if a custom implementation shall be autodetected.
*
*
* @return
*/
@Override
@@ -95,7 +89,6 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
return !hasText(getCustomImplementationRef());
}
/*
* (non-Javadoc)
*
@@ -106,20 +99,16 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
@Override
public String getRepositoryImplementationSuffix() {
String value =
element.getAttribute(RepositoryConfig.REPOSITORY_IMPL_POSTFIX);
return hasText(value) ? value : getParent()
.getRepositoryImplementationSuffix();
String value = element.getAttribute(RepositoryConfig.REPOSITORY_IMPL_POSTFIX);
return hasText(value) ? value : getParent().getRepositoryImplementationSuffix();
}
@Override
public String getTransactionManagerRef() {
return getAttribute(RepositoryConfig.TRANSACTION_MANAGER_REF);
}
/*
* (non-Javadoc)
*
@@ -133,11 +122,9 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
return element;
}
/**
* Returns the attribute of the current context. If it's not set the method
* will fall back to the parent's source.
*
* Returns the attribute of the current context. If it's not set the method will fall back to the parent's source.
*
* @param attribute
* @return
*/
@@ -154,7 +141,6 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
return hasText(value) ? value : null;
}
/*
* (non-Javadoc)
*
@@ -165,13 +151,10 @@ public class ManualRepositoryConfigInformation<T extends CommonRepositoryConfigI
@Override
public String getRepositoryFactoryBeanClassName() {
String value =
element.getAttribute(RepositoryConfig.REPOSITORY_FACTORY_CLASS_NAME);
return hasText(value) ? value : getParent()
.getRepositoryFactoryBeanClassName();
String value = element.getAttribute(RepositoryConfig.REPOSITORY_FACTORY_CLASS_NAME);
return hasText(value) ? value : getParent().getRepositoryFactoryBeanClassName();
}
/*
* (non-Javadoc)
*

View File

@@ -36,14 +36,14 @@ import org.w3c.dom.Element;
* @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
* @param defaultLocation must be non-empty
*/
public NamedQueriesBeanDefinitionParser(String defaultLocation) {
Assert.hasText(defaultLocation);
@@ -55,26 +55,26 @@ public class NamedQueriesBeanDefinitionParser implements BeanDefinitionParser {
* @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.
*
@@ -84,15 +84,15 @@ public class NamedQueriesBeanDefinitionParser implements BeanDefinitionParser {
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;
}

View File

@@ -21,12 +21,10 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.util.Assert;
import org.w3c.dom.Element;
/**
* Base class for {@link SingleRepositoryConfigInformation} implementations. So
* these implementations will capture information for XML elements manually
* configuring a single repository bean.
*
* Base class for {@link SingleRepositoryConfigInformation} implementations. So these implementations will capture
* information for XML elements manually configuring a single repository bean.
*
* @author Oliver Gierke
*/
public abstract class ParentDelegatingRepositoryConfigInformation<T extends CommonRepositoryConfigInformation>
@@ -34,11 +32,10 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
private final T parent;
/**
* Creates a new {@link ParentDelegatingRepositoryConfigInformation} with
* the given {@link CommonRepositoryConfigInformation} as parent.
*
* Creates a new {@link ParentDelegatingRepositoryConfigInformation} with the given
* {@link CommonRepositoryConfigInformation} as parent.
*
* @param parent
*/
public ParentDelegatingRepositoryConfigInformation(T parent) {
@@ -47,7 +44,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
this.parent = parent;
}
/*
* (non-Javadoc)
*
@@ -60,7 +56,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent;
}
/*
* (non-Javadoc)
*
@@ -73,7 +68,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent.getBasePackage();
}
/*
* (non-Javadoc)
*
@@ -86,7 +80,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return capitalize(getBeanId()) + getRepositoryImplementationSuffix();
}
/*
* (non-Javadoc)
*
@@ -99,7 +92,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return getBeanId() + getRepositoryImplementationSuffix();
}
/*
* (non-Javadoc)
*
@@ -112,7 +104,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return true;
}
/*
* (non-Javadoc)
*
@@ -125,7 +116,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return getBeanId() + getRepositoryImplementationSuffix();
}
/*
* (non-Javadoc)
*
@@ -138,7 +128,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent.getSource();
}
/*
* (non-Javadoc)
*
@@ -151,7 +140,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent.getRepositoryImplementationSuffix();
}
/*
* (non-Javadoc)
*
@@ -164,7 +152,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent.getRepositoryFactoryBeanClassName();
}
/*
* (non-Javadoc)
*
@@ -177,7 +164,6 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent.getTransactionManagerRef();
}
/*
* (non-Javadoc)
*
@@ -189,7 +175,7 @@ public abstract class ParentDelegatingRepositoryConfigInformation<T extends Comm
return parent.getQueryLookupStrategyKey();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.CommonRepositoryConfigInformation#getNamedQueriesLocation()

View File

@@ -27,12 +27,10 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Class defining access to the repository configuration abstracting the content
* of the {@code repositories} element in XML namespcae configuration. Defines
* default values to populate resulting repository beans with.
*
* Class defining access to the repository configuration abstracting the content of the {@code repositories} element in
* XML namespcae configuration. Defines default values to populate resulting repository beans with.
*
* @author Oliver Gierke
*/
public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformation<S>, S extends CommonRepositoryConfigInformation>
@@ -41,35 +39,29 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
public static final String DEFAULT_REPOSITORY_IMPL_POSTFIX = "Impl";
public static final String QUERY_LOOKUP_STRATEGY = "query-lookup-strategy";
public static final String BASE_PACKAGE = "base-package";
public static final String REPOSITORY_IMPL_POSTFIX =
"repository-impl-postfix";
public static final String REPOSITORY_IMPL_POSTFIX = "repository-impl-postfix";
public static final String REPOSITORY_FACTORY_CLASS_NAME = "factory-class";
public static final String TRANSACTION_MANAGER_REF =
"transaction-manager-ref";
public static final String TRANSACTION_MANAGER_REF = "transaction-manager-ref";
private final Element element;
private final String defaultRepositoryFactoryBeanClassName;
/**
* Creates an instance of {@code RepositoryConfig}.
*
*
* @param repositoriesElement
*/
protected RepositoryConfig(Element repositoriesElement,
String defaultRepositoryFactoryBeanClassName) {
protected RepositoryConfig(Element repositoriesElement, String defaultRepositoryFactoryBeanClassName) {
Assert.notNull(repositoriesElement, "Element must not be null!");
Assert.notNull(defaultRepositoryFactoryBeanClassName,
"Default repository factory bean class name must not be null!");
this.element = repositoriesElement;
this.defaultRepositoryFactoryBeanClassName =
defaultRepositoryFactoryBeanClassName;
this.defaultRepositoryFactoryBeanClassName = defaultRepositoryFactoryBeanClassName;
}
/*
* (non-Javadoc)
*
@@ -82,7 +74,6 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
return element;
}
/*
* (non-Javadoc)
*
@@ -95,7 +86,6 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
return getRepositoryElements().size() > 0;
}
/*
* (non-Javadoc)
*
@@ -105,14 +95,11 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
*/
public Key getQueryLookupStrategyKey() {
String createFinderQueries =
element.getAttribute(QUERY_LOOKUP_STRATEGY);
String createFinderQueries = element.getAttribute(QUERY_LOOKUP_STRATEGY);
return StringUtils.hasText(createFinderQueries) ? Key
.create(createFinderQueries) : null;
return StringUtils.hasText(createFinderQueries) ? Key.create(createFinderQueries) : null;
}
/*
* (non-Javadoc)
*
@@ -125,7 +112,6 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
return element.getAttribute(BASE_PACKAGE);
}
/*
* (non-Javadoc)
*
@@ -135,13 +121,10 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
*/
public String getRepositoryFactoryBeanClassName() {
String factoryClassName =
getSource().getAttribute(REPOSITORY_FACTORY_CLASS_NAME);
return StringUtils.hasText(factoryClassName) ? factoryClassName
: defaultRepositoryFactoryBeanClassName;
String factoryClassName = getSource().getAttribute(REPOSITORY_FACTORY_CLASS_NAME);
return StringUtils.hasText(factoryClassName) ? factoryClassName : defaultRepositoryFactoryBeanClassName;
}
/*
* (non-Javadoc)
*
@@ -152,11 +135,9 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
public String getRepositoryImplementationSuffix() {
String postfix = element.getAttribute(REPOSITORY_IMPL_POSTFIX);
return StringUtils.hasText(postfix) ? postfix
: DEFAULT_REPOSITORY_IMPL_POSTFIX;
return StringUtils.hasText(postfix) ? postfix : DEFAULT_REPOSITORY_IMPL_POSTFIX;
}
/*
* (non-Javadoc)
*
@@ -170,7 +151,6 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
return StringUtils.hasText(ref) ? ref : null;
}
/*
* (non-Javadoc)
*
@@ -187,16 +167,15 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
return infos;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.GlobalRepositoryConfigInformation#getRepositoryBaseInterface()
*/
public Class<?> getRepositoryBaseInterface() {
return Repository.class;
return Repository.class;
}
private Collection<Element> getRepositoryElements() {
NodeList nodes = element.getChildNodes();
@@ -217,14 +196,11 @@ public abstract class RepositoryConfig<T extends SingleRepositoryConfigInformati
return result;
}
/**
* Creates a {@link SingleRepositoryConfigInformation} for the given
* {@link Element}.
*
* Creates a {@link SingleRepositoryConfigInformation} for the given {@link Element}.
*
* @param element
* @return
*/
protected abstract T createSingleRepositoryConfigInformationFor(
Element element);
protected abstract T createSingleRepositoryConfigInformationFor(Element element);
}

View File

@@ -16,59 +16,51 @@
package org.springframework.data.repository.config;
/**
* Interface to capture configuration information necessary to set up a single
* repository instance.
*
* Interface to capture configuration information necessary to set up a single repository instance.
*
* @author Oliver Gierke
*/
public interface SingleRepositoryConfigInformation<T extends CommonRepositoryConfigInformation>
extends CommonRepositoryConfigInformation {
public interface SingleRepositoryConfigInformation<T extends CommonRepositoryConfigInformation> extends
CommonRepositoryConfigInformation {
/**
* Returns the bean name to be used for the repository.
*
*
* @return
*/
String getBeanId();
/**
* Returns the name of the repository interface.
*
*
* @return
*/
String getInterfaceName();
/**
* Returns the class name of a possible custom repository implementation
* class to detect.
*
* Returns the class name of a possible custom repository implementation class to detect.
*
* @return
*/
String getImplementationClassName();
/**
* Returns the bean name a possibly found custom implementation shall be
* registered under.
*
* Returns the bean name a possibly found custom implementation shall be registered under.
*
* @return
*/
String getImplementationBeanName();
/**
* Returns the bean reference to the custom repository implementation.
*
*
* @return
*/
String getCustomImplementationRef();
/**
* Returns whether to try to autodetect a custom implementation.
*
*
* @return
*/
boolean autodetectCustomImplementation();

View File

@@ -31,12 +31,10 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Parser to populate the given
* {@link ClassPathScanningCandidateComponentProvider} with {@link TypeFilter}s
* parsed from the given {@link Element}'s children.
*
* Parser to populate the given {@link ClassPathScanningCandidateComponentProvider} with {@link TypeFilter}s parsed from
* the given {@link Element}'s children.
*
* @author Oliver Gierke
*/
class TypeFilterParser {
@@ -47,11 +45,9 @@ class TypeFilterParser {
private final ClassLoader classLoader;
private final ReaderContext readerContext;
/**
* Creates a new {@link TypeFilterParser} with the given {@link ClassLoader}
* and {@link ReaderContext}.
*
* Creates a new {@link TypeFilterParser} with the given {@link ClassLoader} and {@link ReaderContext}.
*
* @param classLoader
* @param readerContext
*/
@@ -61,26 +57,20 @@ class TypeFilterParser {
this.readerContext = readerContext;
}
/**
* Parses include and exclude filters form the given {@link Element}'s child
* elements and populates the given
* {@link ClassPathScanningCandidateComponentProvider} with the according
* {@link TypeFilter}s.
*
* Parses include and exclude filters form the given {@link Element}'s child elements and populates the given
* {@link ClassPathScanningCandidateComponentProvider} with the according {@link TypeFilter}s.
*
* @param element
* @param scanner
*/
public void parseFilters(Element element,
ClassPathScanningCandidateComponentProvider scanner) {
public void parseFilters(Element element, ClassPathScanningCandidateComponentProvider scanner) {
parseTypeFilters(element, scanner, Type.INCLUDE);
parseTypeFilters(element, scanner, Type.EXCLUDE);
}
private void parseTypeFilters(Element element,
ClassPathScanningCandidateComponentProvider scanner, Type type) {
private void parseTypeFilters(Element element, ClassPathScanningCandidateComponentProvider scanner, Type type) {
NodeList nodeList = element.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
@@ -92,21 +82,16 @@ class TypeFilterParser {
try {
type.addFilter(
createTypeFilter((Element) node, classLoader),
scanner);
type.addFilter(createTypeFilter((Element) node, classLoader), scanner);
} catch (RuntimeException e) {
readerContext.error(e.getMessage(),
readerContext.extractSource(element), e.getCause());
readerContext.error(e.getMessage(), readerContext.extractSource(element), e.getCause());
}
}
}
}
protected TypeFilter createTypeFilter(Element element,
ClassLoader classLoader) {
protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader) {
String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
@@ -117,16 +102,14 @@ class TypeFilterParser {
return filter.getFilter(expression, classLoader);
} catch (ClassNotFoundException ex) {
throw new FatalBeanException("Type filter class not found: "
+ expression, ex);
throw new FatalBeanException("Type filter class not found: " + expression, ex);
}
}
/**
* Enum representing all the filter types available for {@code include} and
* {@code exclude} elements. This acts as factory for {@link TypeFilter}
* instances.
*
* Enum representing all the filter types available for {@code include} and {@code exclude} elements. This acts as
* factory for {@link TypeFilter} instances.
*
* @author Oliver Gierke
* @see #getFilter(String, ClassLoader)
*/
@@ -135,29 +118,24 @@ class TypeFilterParser {
ANNOTATION {
@Override
@SuppressWarnings("unchecked")
public TypeFilter getFilter(String expression,
ClassLoader classLoader) throws ClassNotFoundException {
public TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException {
return new AnnotationTypeFilter(
(Class<Annotation>) classLoader.loadClass(expression));
return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
}
},
ASSIGNABLE {
@Override
public TypeFilter getFilter(String expression,
ClassLoader classLoader) throws ClassNotFoundException {
public TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException {
return new AssignableTypeFilter(
classLoader.loadClass(expression));
return new AssignableTypeFilter(classLoader.loadClass(expression));
}
},
ASPECTJ {
@Override
public TypeFilter getFilter(String expression,
ClassLoader classLoader) {
public TypeFilter getFilter(String expression, ClassLoader classLoader) {
return new AspectJTypeFilter(expression, classLoader);
}
@@ -166,8 +144,7 @@ class TypeFilterParser {
REGEX {
@Override
public TypeFilter getFilter(String expression,
ClassLoader classLoader) {
public TypeFilter getFilter(String expression, ClassLoader classLoader) {
return new RegexPatternTypeFilter(Pattern.compile(expression));
}
@@ -176,40 +153,33 @@ class TypeFilterParser {
CUSTOM {
@Override
public TypeFilter getFilter(String expression,
ClassLoader classLoader) throws ClassNotFoundException {
public TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException {
Class<?> filterClass = classLoader.loadClass(expression);
if (!TypeFilter.class.isAssignableFrom(filterClass)) {
throw new IllegalArgumentException(
"Class is not assignable to ["
+ TypeFilter.class.getName() + "]: "
+ expression);
throw new IllegalArgumentException("Class is not assignable to [" + TypeFilter.class.getName() + "]: "
+ expression);
}
return (TypeFilter) BeanUtils.instantiateClass(filterClass);
}
};
/**
* Returns the {@link TypeFilter} for the given expression and
* {@link ClassLoader}.
*
* Returns the {@link TypeFilter} for the given expression and {@link ClassLoader}.
*
* @param expression
* @param classLoader
* @return
* @throws ClassNotFoundException
*/
abstract TypeFilter getFilter(String expression, ClassLoader classLoader)
throws ClassNotFoundException;
abstract TypeFilter getFilter(String expression, ClassLoader classLoader) throws ClassNotFoundException;
/**
* Returns the {@link FilterType} for the given type as {@link String}.
*
*
* @param typeString
* @return
* @throws IllegalArgumentException if no {@link FilterType} could be
* found for the given argument.
* @throws IllegalArgumentException if no {@link FilterType} could be found for the given argument.
*/
static FilterType fromString(String typeString) {
@@ -219,8 +189,7 @@ class TypeFilterParser {
}
}
throw new IllegalArgumentException("Unsupported filter type: "
+ typeString);
throw new IllegalArgumentException("Unsupported filter type: " + typeString);
}
}
@@ -228,8 +197,7 @@ class TypeFilterParser {
INCLUDE("include-filter") {
@Override
public void addFilter(TypeFilter filter,
ClassPathScanningCandidateComponentProvider scanner) {
public void addFilter(TypeFilter filter, ClassPathScanningCandidateComponentProvider scanner) {
scanner.addIncludeFilter(filter);
}
@@ -237,8 +205,7 @@ class TypeFilterParser {
},
EXCLUDE("exclude-filter") {
@Override
public void addFilter(TypeFilter filter,
ClassPathScanningCandidateComponentProvider scanner) {
public void addFilter(TypeFilter filter, ClassPathScanningCandidateComponentProvider scanner) {
scanner.addExcludeFilter(filter);
}
@@ -246,17 +213,15 @@ class TypeFilterParser {
private String elementName;
private Type(String elementName) {
this.elementName = elementName;
}
/**
* Returns the {@link Element} if the given {@link Node} is an
* {@link Element} and it's name equals the one of the type.
*
* Returns the {@link Element} if the given {@link Node} is an {@link Element} and it's name equals the one of the
* type.
*
* @param node
* @return
*/
@@ -272,8 +237,6 @@ class TypeFilterParser {
return null;
}
abstract void addFilter(TypeFilter filter,
ClassPathScanningCandidateComponentProvider scanner);
abstract void addFilter(TypeFilter filter, ClassPathScanningCandidateComponentProvider scanner);
}
}

View File

@@ -18,25 +18,23 @@ package org.springframework.data.repository.core;
import java.io.Serializable;
/**
* Extension of {@link EntityMetadata} to add functionality to query information
* of entity instances.
*
* Extension of {@link EntityMetadata} to add functionality to query information of entity instances.
*
* @author Oliver Gierke
*/
public interface EntityInformation<T, ID extends Serializable> extends EntityMetadata<T> {
/**
* Returns whether the given entity is considered to be new.
*
*
* @param entity must never be {@literal null}
* @return
*/
boolean isNew(T entity);
/**
* Returns the id of the given entity.
*
*
* @param entity must never be {@literal null}
* @return
*/
@@ -44,7 +42,7 @@ public interface EntityInformation<T, ID extends Serializable> extends EntityMet
/**
* Returns the type of the id of the entity.
*
*
* @return
*/
Class<ID> getIdType();

View File

@@ -17,14 +17,14 @@ package org.springframework.data.repository.core;
/**
* Metadata for entity types.
*
*
* @author Oliver Gierke
*/
public interface EntityMetadata<T> {
/**
* Returns the actual domain class type.
*
*
* @return
*/
Class<T> getJavaType();

View File

@@ -17,7 +17,7 @@ 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 {

View File

@@ -19,55 +19,48 @@ import java.lang.reflect.Method;
/**
* Aditional repository specific information
*
*
* @author Oliver Gierke
*/
public interface RepositoryInformation extends RepositoryMetadata {
/**
* Returns the base class to be used to create the proxy backing instance.
*
*
* @return
*/
Class<?> getRepositoryBaseClass();
/**
* Returns if the configured repository interface has custom methods, that
* might have to be delegated to a custom implementation. This is used to
* verify repository configuration.
*
* Returns if the configured repository interface has custom methods, that might have to be delegated to a custom
* implementation. This is used to verify repository configuration.
*
* @return
*/
boolean hasCustomMethod();
/**
* Returns whether the given method is a custom repository method.
*
*
* @param method
* @param baseClass
* @return
*/
boolean isCustomMethod(Method method);
/**
* Returns all methods considered to be query methods.
*
*
* @param repositoryInterface
* @return
*/
Iterable<Method> getQueryMethods();
/**
* Returns the target class method that is backing the given method. This can
* be necessary if a repository interface redeclares a method of the core
* repository interface (e.g. for transaction behaviour customization).
* Returns the method itself if the target class does not implement the given
* method.
*
* Returns the target class method that is backing the given method. This can be necessary if a repository interface
* redeclares a method of the core repository interface (e.g. for transaction behaviour customization). Returns the
* method itself if the target class does not implement the given method.
*
* @param method
* @return
*/

View File

@@ -15,35 +15,32 @@
*/
package org.springframework.data.repository.core;
/**
* Metadata for repository interfaces.
*
*
* @author Oliver Gierke
*/
public interface RepositoryMetadata {
/**
* Returns the id class the given class is declared for.
*
*
* @param clazz
* @return the id class of the entity managed by the repository for or
* {@code null} if none found.
* @return the id class of the entity managed by the repository for or {@code null} if none found.
*/
Class<?> getIdClass();
/**
* Returns the domain class the repository is declared for.
*
*
* @param clazz
* @return the domain class the repository is handling or {@code null} if
* none found.
* @return the domain class the repository is handling or {@code null} if none found.
*/
Class<?> getDomainClass();
/**
* Returns the repository interface.
*
*
* @return
*/
Class<?> getRepositoryInterface();

View File

@@ -20,23 +20,19 @@ import java.io.Serializable;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.util.Assert;
/**
* Base class for implementations of {@link EntityInformation}. Considers an
* entity to be new whenever {@link #getId(Object)} returns {@literal null}.
*
* Base class for implementations of {@link EntityInformation}. Considers an entity to be new whenever
* {@link #getId(Object)} returns {@literal null}.
*
* @author Oliver Gierke
*/
public abstract class AbstractEntityInformation<T, ID extends Serializable> implements
EntityInformation<T, ID> {
public abstract class AbstractEntityInformation<T, ID extends Serializable> implements EntityInformation<T, ID> {
private final Class<T> domainClass;
/**
* Creates a new {@link AbstractEntityInformation} from the given domain
* class.
*
* Creates a new {@link AbstractEntityInformation} from the given domain class.
*
* @param domainClass
*/
public AbstractEntityInformation(Class<T> domainClass) {
@@ -45,7 +41,6 @@ public abstract class AbstractEntityInformation<T, ID extends Serializable> impl
this.domainClass = domainClass;
}
/*
* (non-Javadoc)
*
@@ -58,7 +53,6 @@ public abstract class AbstractEntityInformation<T, ID extends Serializable> impl
return getId(entity) == null;
}
/*
* (non-Javadoc)
*

View File

@@ -20,18 +20,18 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.util.Assert;
/**
* {@link RepositoryMetadata} implementation inspecting the given repository interface for a {@link RepositoryDefinition}
* annotation.
* {@link RepositoryMetadata} implementation inspecting the given repository interface for a
* {@link RepositoryDefinition} annotation.
*
* @author Oliver Gierke
*/
public class AnnotationRepositoryMetadata implements RepositoryMetadata {
private static final String NO_ANNOTATION_FOUND = String.format("Interface must be annotated with @%s!",
RepositoryDefinition.class.getName());
private final Class<?> repositoryInterface;
public AnnotationRepositoryMetadata(Class<?> repositoryInterface) {
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
Assert.isTrue(repositoryInterface.isAnnotationPresent(RepositoryDefinition.class), NO_ANNOTATION_FOUND);

View File

@@ -34,7 +34,7 @@ import org.springframework.util.Assert;
/**
* Default implementation of {@link RepositoryInformation}.
*
*
* @author Oliver Gierke
*/
class DefaultRepositoryInformation implements RepositoryInformation {
@@ -52,12 +52,13 @@ class DefaultRepositoryInformation implements RepositoryInformation {
/**
* Creates a new {@link DefaultRepositoryMetadata} for the given repository interface and repository base class.
*
*
* @param metadata
* @param repositoryBaseClass
* @param customImplementationClass
*/
public DefaultRepositoryInformation(RepositoryMetadata metadata, Class<?> repositoryBaseClass, Class<?> customImplementationClass) {
public DefaultRepositoryInformation(RepositoryMetadata metadata, Class<?> repositoryBaseClass,
Class<?> customImplementationClass) {
Assert.notNull(metadata);
Assert.notNull(repositoryBaseClass);
@@ -104,18 +105,18 @@ class DefaultRepositoryInformation implements RepositoryInformation {
* @see org.springframework.data.repository.support.RepositoryInformation#getTargetClassMethod(java.lang.reflect.Method)
*/
public Method getTargetClassMethod(Method method) {
if (methodCache.containsKey(method)) {
return methodCache.get(method);
}
Method result = getTargetClassMethod(method, customImplementationClass);
if (!result.equals(method)) {
methodCache.put(method, result);
return result;
}
result = getTargetClassMethod(method, repositoryBaseClass);
methodCache.put(method, result);
return result;
@@ -123,14 +124,14 @@ class DefaultRepositoryInformation implements RepositoryInformation {
/**
* Returns whether the given method is considered to be a repository base class method.
*
*
* @param method
* @return
*/
private boolean isTargetClassMethod(Method method, Class<?> targetType) {
Assert.notNull(method);
if (targetType == null) {
return false;
}
@@ -141,7 +142,6 @@ class DefaultRepositoryInformation implements RepositoryInformation {
return !method.equals(getTargetClassMethod(method, targetType));
}
/*
* (non-Javadoc)
@@ -167,10 +167,10 @@ class DefaultRepositoryInformation implements RepositoryInformation {
public boolean isCustomMethod(Method method) {
return isTargetClassMethod(method, customImplementationClass);
}
/**
* Returns whether the given method is a method covered by the base implementation.
*
*
* @param method
* @return
*/
@@ -180,15 +180,15 @@ class DefaultRepositoryInformation implements RepositoryInformation {
/**
* Returns the given target class' method if the given method (declared in the repository interface) was also declared
* at the target class. Returns the given method if the given base class does not declare the method given.
* Takes generics into account.
*
* at the target class. Returns the given method if the given base class does not declare the method given. Takes
* generics into account.
*
* @param method must not be {@literal null}
* @param baseClass
* @return
*/
Method getTargetClassMethod(Method method, Class<?> baseClass) {
if (baseClass == null) {
return method;
}
@@ -241,7 +241,7 @@ class DefaultRepositoryInformation implements RepositoryInformation {
/**
* Checks the given method's parameters to match the ones of the given base class method. Matches generic arguments
* agains the ones bound in the given repository interface.
*
*
* @param method
* @param baseClassMethod
* @return
@@ -276,7 +276,7 @@ class DefaultRepositoryInformation implements RepositoryInformation {
* Checks whether the given parameter type matches the generic type of the given parameter. Thus when {@literal PK} is
* declared, the method ensures that given method parameter is the primary key type declared in the given repository
* interface e.g.
*
*
* @param name
* @param parameterType
* @return

View File

@@ -22,8 +22,8 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.util.Assert;
/**
* Default implementation of {@link RepositoryMetadata}. Will inspect generic types of
* {@link Repository} to find out about domain and id class.
* Default implementation of {@link RepositoryMetadata}. Will inspect generic types of {@link Repository} to find out
* about domain and id class.
*
* @author Oliver Gierke
*/
@@ -31,11 +31,9 @@ public class DefaultRepositoryMetadata implements RepositoryMetadata {
private final Class<?> repositoryInterface;
/**
* Creates a new {@link DefaultRepositoryMetadata} for the given repository
* interface.
*
* Creates a new {@link DefaultRepositoryMetadata} for the given repository interface.
*
* @param repositoryInterface
*/
public DefaultRepositoryMetadata(Class<?> repositoryInterface) {
@@ -45,7 +43,6 @@ public class DefaultRepositoryMetadata implements RepositoryMetadata {
this.repositoryInterface = repositoryInterface;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
@@ -55,27 +52,23 @@ public class DefaultRepositoryMetadata implements RepositoryMetadata {
return repositoryInterface;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
*/
public Class<?> getDomainClass() {
Class<?>[] arguments =
resolveTypeArguments(repositoryInterface, Repository.class);
Class<?>[] arguments = resolveTypeArguments(repositoryInterface, Repository.class);
return arguments == null ? null : arguments[0];
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
*/
public Class<?> getIdClass() {
Class<?>[] arguments =
resolveTypeArguments(repositoryInterface, Repository.class);
Class<?>[] arguments = resolveTypeArguments(repositoryInterface, Repository.class);
return arguments == null ? null : arguments[1];
}
}

View File

@@ -21,12 +21,10 @@ import org.springframework.core.GenericTypeResolver;
import org.springframework.data.domain.Persistable;
import org.springframework.data.repository.core.EntityMetadata;
/**
* Implementation of {@link EntityMetadata} that assumes the entity handled
* implements {@link Persistable} and uses {@link Persistable#isNew()} for the
* {@link #isNew(Object)} check.
*
* Implementation of {@link EntityMetadata} that assumes the entity handled implements {@link Persistable} and uses
* {@link Persistable#isNew()} for the {@link #isNew(Object)} check.
*
* @author Oliver Gierke
*/
public class PersistableEntityInformation<T extends Persistable<ID>, ID extends Serializable> extends
@@ -36,7 +34,7 @@ public class PersistableEntityInformation<T extends Persistable<ID>, ID extends
/**
* Creates a new {@link PersistableEntityInformation}.
*
*
* @param domainClass
*/
@SuppressWarnings("unchecked")
@@ -46,7 +44,6 @@ public class PersistableEntityInformation<T extends Persistable<ID>, ID extends
this.idClass = (Class<ID>) GenericTypeResolver.resolveTypeArgument(domainClass, Persistable.class);
}
/*
* (non-Javadoc)
*
@@ -60,7 +57,6 @@ public class PersistableEntityInformation<T extends Persistable<ID>, ID extends
return entity.isNew();
}
/*
* (non-Javadoc)
*

View File

@@ -22,15 +22,15 @@ 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());
public static NamedQueries EMPTY = new PropertiesBasedNamedQueries(new Properties());
private final Properties properties;
/**
* Creates a new {@link PropertiesBasedNamedQueries} for the given {@link Properties} instance.
*
@@ -40,14 +40,14 @@ public class PropertiesBasedNamedQueries implements NamedQueries {
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)
*/

View File

@@ -17,18 +17,16 @@ package org.springframework.data.repository.core.support;
import org.springframework.data.repository.query.RepositoryQuery;
/**
* Callback for listeners that want to execute functionality on
* {@link RepositoryQuery} creation.
*
* Callback for listeners that want to execute functionality on {@link RepositoryQuery} creation.
*
* @author Oliver Gierke
*/
public interface QueryCreationListener<T extends RepositoryQuery> {
/**
* Will be invoked just after the {@link RepositoryQuery} was created.
*
*
* @param query
*/
void onCreation(T query);

View File

@@ -28,16 +28,15 @@ import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.util.Assert;
/**
* Adapter for Springs {@link FactoryBean} interface to allow easy setup of
* repository factories via Spring configuration.
*
* Adapter for Springs {@link FactoryBean} interface to allow easy setup of repository factories via Spring
* configuration.
*
* @param <T> the type of the repository
* @author Oliver Gierke
*/
public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID extends Serializable>
implements InitializingBean, RepositoryFactoryInformation<S, ID>, FactoryBean<T> {
public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID extends Serializable> implements
InitializingBean, RepositoryFactoryInformation<S, ID>, FactoryBean<T> {
private RepositoryFactorySupport factory;
@@ -46,10 +45,9 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
private Object customImplementation;
private NamedQueries namedQueries;
/**
* Setter to inject the repository interface to implement.
*
*
* @param repositoryInterface the repository interface to set
*/
@Required
@@ -59,10 +57,9 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
this.repositoryInterface = repositoryInterface;
}
/**
* Set the {@link QueryLookupStrategy.Key} to be used.
*
*
* @param queryLookupStrategyKey
*/
public void setQueryLookupStrategyKey(Key queryLookupStrategyKey) {
@@ -70,10 +67,9 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
this.queryLookupStrategyKey = queryLookupStrategyKey;
}
/**
* Setter to inject a custom repository implementation.
*
*
* @param customImplementation
*/
public void setCustomImplementation(Object customImplementation) {
@@ -81,7 +77,6 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
this.customImplementation = customImplementation;
}
/**
* Setter to inject a {@link NamedQueries} instance.
*
@@ -101,7 +96,6 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
return (EntityInformation<S, ID>) factory.getEntityInformation(repositoryMetadata.getDomainClass());
}
/* (non-Javadoc)
* @see org.springframework.data.repository.support.RepositoryFactoryInformation#getRepositoryInterface()
*/
@@ -120,7 +114,6 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
return factory.getRepository(repositoryInterface, customImplementation);
}
/*
* (non-Javadoc)
*
@@ -129,11 +122,9 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
@SuppressWarnings("unchecked")
public Class<? extends T> getObjectType() {
return (Class<? extends T>) (null == repositoryInterface ? Repository.class
: repositoryInterface);
return (Class<? extends T>) (null == repositoryInterface ? Repository.class : repositoryInterface);
}
/*
* (non-Javadoc)
*
@@ -144,7 +135,6 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
return true;
}
/*
* (non-Javadoc)
*
@@ -158,10 +148,9 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
this.factory.setNamedQueries(namedQueries);
}
/**
* Create the actual {@link RepositoryFactorySupport} instance.
*
*
* @return
*/
protected abstract RepositoryFactorySupport createRepositoryFactory();

View File

@@ -20,26 +20,23 @@ import java.io.Serializable;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.EntityInformation;
/**
* Interface for components that can provide {@link EntityInformation} this
* interface
*
* Interface for components that can provide {@link EntityInformation} this interface
*
* @author Oliver Gierke
*/
public interface RepositoryFactoryInformation<T, ID extends Serializable> {
/**
* Returns {@link EntityInformation} the repository factory is using.
*
*
* @return
*/
EntityInformation<T, ID> getEntityInformation();
/**
* Returns the interface of the {@link Repository} the factory will create.
*
*
* @return
*/
Class<? extends Repository<T, ID>> getRepositoryInterface();

View File

@@ -40,35 +40,30 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.util.ClassUtils;
import org.springframework.util.Assert;
/**
* Factory bean to create instances of a given repository interface. Creates a
* proxy implementing the configured repository interface and apply an advice
* handing the control to the {@code QueryExecuterMethodInterceptor}. Query
* detection strategy can be configured by setting
* {@link QueryLookupStrategy.Key}.
*
* Factory bean to create instances of a given repository interface. Creates a proxy implementing the configured
* repository interface and apply an advice handing the control to the {@code QueryExecuterMethodInterceptor}. Query
* detection strategy can be configured by setting {@link QueryLookupStrategy.Key}.
*
* @author Oliver Gierke
*/
public abstract class RepositoryFactorySupport {
private final List<RepositoryProxyPostProcessor> postProcessors =
new ArrayList<RepositoryProxyPostProcessor>();
private final List<RepositoryProxyPostProcessor> postProcessors = new ArrayList<RepositoryProxyPostProcessor>();
private QueryLookupStrategy.Key queryLookupStrategyKey;
private List<QueryCreationListener<?>> queryPostProcessors =
new ArrayList<QueryCreationListener<?>>();
private List<QueryCreationListener<?>> queryPostProcessors = new ArrayList<QueryCreationListener<?>>();
private NamedQueries namedQueries = PropertiesBasedNamedQueries.EMPTY;
/**
* Sets the strategy of how to lookup a query to execute finders.
*
*
* @param queryLookupStrategy the createFinderQueries to set
*/
public void setQueryLookupStrategyKey(Key key) {
this.queryLookupStrategyKey = key;
}
/**
* Configures a {@link NamedQueries} instance to be handed to the {@link QueryLookupStrategy} for query creation.
*
@@ -78,12 +73,10 @@ public abstract class RepositoryFactorySupport {
this.namedQueries = namedQueries == null ? PropertiesBasedNamedQueries.EMPTY : namedQueries;
}
/**
* Adds a {@link QueryCreationListener} to the factory to plug in
* functionality triggered right after creation of {@link RepositoryQuery}
* instances.
*
* Adds a {@link QueryCreationListener} to the factory to plug in functionality triggered right after creation of
* {@link RepositoryQuery} instances.
*
* @param listener
*/
public void addQueryCreationListener(QueryCreationListener<?> listener) {
@@ -92,50 +85,42 @@ public abstract class RepositoryFactorySupport {
this.queryPostProcessors.add(listener);
}
/**
* Adds {@link RepositoryProxyPostProcessor}s to the factory to allow
* manipulation of the {@link ProxyFactory} before the proxy gets created.
* Note that the {@link QueryExecutorMethodInterceptor} will be added to the
* proxy <em>after</em> the {@link RepositoryProxyPostProcessor}s are
* considered.
*
* Adds {@link RepositoryProxyPostProcessor}s to the factory to allow manipulation of the {@link ProxyFactory} before
* the proxy gets created. Note that the {@link QueryExecutorMethodInterceptor} will be added to the proxy
* <em>after</em> the {@link RepositoryProxyPostProcessor}s are considered.
*
* @param processor
*/
public void addRepositoryProxyPostProcessor(
RepositoryProxyPostProcessor processor) {
public void addRepositoryProxyPostProcessor(RepositoryProxyPostProcessor processor) {
Assert.notNull(processor);
this.postProcessors.add(processor);
}
/**
* Returns a repository instance for the given interface.
*
*
* @param <T>
* @param repositoryInterface
* @return
*/
public <T extends Repository<?, ?>> T getRepository(
Class<T> repositoryInterface) {
public <T extends Repository<?, ?>> T getRepository(Class<T> repositoryInterface) {
return getRepository(repositoryInterface, null);
}
/**
* Returns a repository instance for the given interface backed by an
* instance providing implementation logic for custom logic.
*
* Returns a repository instance for the given interface backed by an instance providing implementation logic for
* custom logic.
*
* @param <T>
* @param repositoryInterface
* @param customImplementation
* @return
*/
@SuppressWarnings({"unchecked"})
public <T> T getRepository(Class<T> repositoryInterface,
Object customImplementation) {
@SuppressWarnings({ "unchecked" })
public <T> T getRepository(Class<T> repositoryInterface, Object customImplementation) {
RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);
Class<?> customImplementationClass = null == customImplementation ? null : customImplementation.getClass();
@@ -148,21 +133,20 @@ public abstract class RepositoryFactorySupport {
// Create proxy
ProxyFactory result = new ProxyFactory();
result.setTarget(target);
result.setInterfaces(new Class[]{repositoryInterface});
result.setInterfaces(new Class[] { repositoryInterface });
for (RepositoryProxyPostProcessor processor : postProcessors) {
processor.postProcess(result);
}
result.addAdvice(new QueryExecutorMethodInterceptor(information,
customImplementation, target));
result.addAdvice(new QueryExecutorMethodInterceptor(information, customImplementation, target));
return (T) result.getProxy();
}
/**
* Returns the {@link RepositoryMetadata} for the given repository interface.
*
*
* @param repositoryInterface
* @return
*/
@@ -171,10 +155,9 @@ public abstract class RepositoryFactorySupport {
: new AnnotationRepositoryMetadata(repositoryInterface);
}
/**
* Returns the {@link RepositoryInformation} for the given repository interface.
*
*
* @param repositoryInterface
* @param customImplementationClass
* @return
@@ -183,41 +166,36 @@ public abstract class RepositoryFactorySupport {
return new DefaultRepositoryInformation(metadata, getRepositoryBaseClass(metadata), customImplementationClass);
}
/**
* Returns the {@link EntityInformation} for the given domain class.
*
* @param <T> the entity type
* @param <ID> the id type
*
* @param <T> the entity type
* @param <ID> the id type
* @param domainClass
* @return
*/
public abstract <T, ID extends Serializable> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass);
/**
* Create a repository instance as backing for the query proxy.
*
*
* @param metadata
* @return
*/
protected abstract Object getTargetRepository(RepositoryMetadata metadata);
/**
* Returns the base class backing the actual repository instance. Make sure
* {@link #getTargetRepository(RepositoryMetadata)} returns an instance of
* this class.
*
* {@link #getTargetRepository(RepositoryMetadata)} returns an instance of this class.
*
* @param metadata
* @return
*/
protected abstract Class<?> getRepositoryBaseClass(
RepositoryMetadata metadata);
protected abstract Class<?> getRepositoryBaseClass(RepositoryMetadata metadata);
/**
* Returns the {@link QueryLookupStrategy} for the given {@link Key}.
*
*
* @param key can be {@literal null}
* @return the {@link QueryLookupStrategy} to use or {@literal null} if no queries should be looked up.
*/
@@ -225,24 +203,19 @@ public abstract class RepositoryFactorySupport {
return null;
}
/**
* Validates the given repository interface as well as the given custom
* implementation.
*
* Validates the given repository interface as well as the given custom implementation.
*
* @param repositoryInformation
* @param customImplementation
*/
private void validate(RepositoryInformation repositoryInformation,
Object customImplementation) {
private void validate(RepositoryInformation repositoryInformation, Object customImplementation) {
if (null == customImplementation
&& repositoryInformation.hasCustomMethod()) {
if (null == customImplementation && repositoryInformation.hasCustomMethod()) {
throw new IllegalArgumentException(
String.format(
"You have custom methods in %s but not provided a custom implementation!",
repositoryInformation.getRepositoryInterface()));
throw new IllegalArgumentException(String.format(
"You have custom methods in %s but not provided a custom implementation!",
repositoryInformation.getRepositoryInterface()));
}
validate(repositoryInformation);
@@ -253,77 +226,63 @@ public abstract class RepositoryFactorySupport {
}
/**
* This {@code MethodInterceptor} intercepts calls to methods of the custom
* implementation and delegates the to it if configured. Furthermore it
* resolves method calls to finders and triggers execution of them. You can
* rely on having a custom repository implementation instance set if this
* returns true.
*
* This {@code MethodInterceptor} intercepts calls to methods of the custom implementation and delegates the to it if
* configured. Furthermore it resolves method calls to finders and triggers execution of them. You can rely on having
* a custom repository implementation instance set if this returns true.
*
* @author Oliver Gierke
*/
public class QueryExecutorMethodInterceptor implements MethodInterceptor {
private final Map<Method, RepositoryQuery> queries =
new ConcurrentHashMap<Method, RepositoryQuery>();
private final Map<Method, RepositoryQuery> queries = new ConcurrentHashMap<Method, RepositoryQuery>();
private final Object customImplementation;
private final RepositoryInformation repositoryInformation;
private final Object target;
/**
* Creates a new {@link QueryExecutorMethodInterceptor}. Builds a model
* of {@link QueryMethod}s to be invoked on execution of repository
* interface methods.
* Creates a new {@link QueryExecutorMethodInterceptor}. Builds a model of {@link QueryMethod}s to be invoked on
* execution of repository interface methods.
*/
public QueryExecutorMethodInterceptor(
RepositoryInformation repositoryInformation,
Object customImplementation, Object target) {
public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation, Object customImplementation,
Object target) {
this.repositoryInformation = repositoryInformation;
this.customImplementation = customImplementation;
this.target = target;
QueryLookupStrategy lookupStrategy =
getQueryLookupStrategy(queryLookupStrategyKey);
QueryLookupStrategy lookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey);
if (lookupStrategy == null) {
if (repositoryInformation.hasCustomMethod()) {
throw new IllegalStateException(
"You have defined query method in the repository but " +
"you don't have no query lookup strategy defined. The " +
"infrastructure apparently does not support query methods!");
throw new IllegalStateException("You have defined query method in the repository but "
+ "you don't have no query lookup strategy defined. The "
+ "infrastructure apparently does not support query methods!");
}
return;
}
for (Method method : repositoryInformation.getQueryMethods()) {
RepositoryQuery query =
lookupStrategy.resolveQuery(method, repositoryInformation, namedQueries);
RepositoryQuery query = lookupStrategy.resolveQuery(method, repositoryInformation, namedQueries);
invokeListeners(query);
queries.put(method, query);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
@SuppressWarnings({ "rawtypes", "unchecked" })
private void invokeListeners(RepositoryQuery query) {
for (QueryCreationListener listener : queryPostProcessors) {
Class<?> typeArgument =
GenericTypeResolver.resolveTypeArgument(
listener.getClass(),
QueryCreationListener.class);
if (typeArgument != null
&& typeArgument.isAssignableFrom(query.getClass())) {
Class<?> typeArgument = GenericTypeResolver.resolveTypeArgument(listener.getClass(),
QueryCreationListener.class);
if (typeArgument != null && typeArgument.isAssignableFrom(query.getClass())) {
listener.onCreation(query);
}
}
}
/*
* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
@@ -335,8 +294,7 @@ public abstract class RepositoryFactorySupport {
if (isCustomMethodInvocation(invocation)) {
Method actualMethod = repositoryInformation.getTargetClassMethod(method);
makeAccessible(actualMethod);
return executeMethodOn(customImplementation, actualMethod,
invocation.getArguments());
return executeMethodOn(customImplementation, actualMethod, invocation.getArguments());
}
if (hasQueryFor(method)) {
@@ -346,23 +304,19 @@ public abstract class RepositoryFactorySupport {
// Lookup actual method as it might be redeclared in the interface
// and we have to use the repository instance nevertheless
Method actualMethod = repositoryInformation.getTargetClassMethod(method);
return executeMethodOn(target, actualMethod,
invocation.getArguments());
return executeMethodOn(target, actualMethod, invocation.getArguments());
}
/**
* Executes the given method on the given target. Correctly unwraps
* exceptions not caused by the reflection magic.
*
* Executes the given method on the given target. Correctly unwraps exceptions not caused by the reflection magic.
*
* @param target
* @param method
* @param parameters
* @return
* @throws Throwable
*/
private Object executeMethodOn(Object target, Method method,
Object[] parameters) throws Throwable {
private Object executeMethodOn(Object target, Method method, Object[] parameters) throws Throwable {
try {
return method.invoke(target, parameters);
@@ -373,11 +327,9 @@ public abstract class RepositoryFactorySupport {
throw new IllegalStateException("Should not occur!");
}
/**
* Returns whether we know of a query to execute for the given
* {@link Method};
*
* Returns whether we know of a query to execute for the given {@link Method};
*
* @param method
* @return
*/
@@ -386,11 +338,10 @@ public abstract class RepositoryFactorySupport {
return queries.containsKey(method);
}
/**
* Returns whether the given {@link MethodInvocation} is considered to
* be targeted as an invocation of a custom method.
*
* Returns whether the given {@link MethodInvocation} is considered to be targeted as an invocation of a custom
* method.
*
* @param method
* @return
*/
@@ -399,8 +350,6 @@ public abstract class RepositoryFactorySupport {
if (null == customImplementation) {
return false;
}
return repositoryInformation.isCustomMethod(invocation.getMethod());
}

View File

@@ -17,19 +17,17 @@ package org.springframework.data.repository.core.support;
import org.springframework.aop.framework.ProxyFactory;
/**
* Callback interface used during repository proxy creation. Allows manipulating
* the {@link ProxyFactory} creating the repository.
*
* Callback interface used during repository proxy creation. Allows manipulating the {@link ProxyFactory} creating the
* repository.
*
* @author Oliver Gierke
*/
public interface RepositoryProxyPostProcessor {
/**
* Manipulates the {@link ProxyFactory}, e.g. add further interceptors to
* it.
*
* Manipulates the {@link ProxyFactory}, e.g. add further interceptors to it.
*
* @param factory
*/
void postProcess(ProxyFactory factory);

View File

@@ -25,13 +25,11 @@ import org.springframework.data.repository.util.TxUtils;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.util.Assert;
/**
* Extension of {@link RepositoryFactoryBeanSupport} to add transactional
* capabilities to the repository proxy. Will register a
* {@link TransactionalRepositoryProxyPostProcessor} that in turn adds a
* {@link TransactionInterceptor} to the repository proxy to be created.
*
* Extension of {@link RepositoryFactoryBeanSupport} to add transactional capabilities to the repository proxy. Will
* register a {@link TransactionalRepositoryProxyPostProcessor} that in turn adds a {@link TransactionInterceptor} to
* the repository proxy to be created.
*
* @author Oliver Gierke
*/
public abstract class TransactionalRepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID extends Serializable>
@@ -40,32 +38,23 @@ public abstract class TransactionalRepositoryFactoryBeanSupport<T extends Reposi
private String transactionManagerName = TxUtils.DEFAULT_TRANSACTION_MANAGER;
private RepositoryProxyPostProcessor txPostProcessor;
/**
* Setter to configure which transaction manager to be used. We have to use
* the bean name explicitly as otherwise the qualifier of the
* {@link org.springframework.transaction.annotation.Transactional}
* annotation is used. By explicitly defining the transaction manager bean
* name we favour let this one be the default one chosen.
*
* Setter to configure which transaction manager to be used. We have to use the bean name explicitly as otherwise the
* qualifier of the {@link org.springframework.transaction.annotation.Transactional} annotation is used. By explicitly
* defining the transaction manager bean name we favour let this one be the default one chosen.
*
* @param transactionManager
*/
public void setTransactionManager(String transactionManager) {
this.transactionManagerName =
transactionManager == null ? TxUtils.DEFAULT_TRANSACTION_MANAGER
: transactionManager;
this.transactionManagerName = transactionManager == null ? TxUtils.DEFAULT_TRANSACTION_MANAGER : transactionManager;
}
/**
* Delegates {@link RepositoryFactorySupport} creation to
* {@link #doCreateRepositoryFactory()} and applies the
* {@link TransactionalRepositoryProxyPostProcessor} to the created
* instance.
*
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport
* #createRepositoryFactory()
* Delegates {@link RepositoryFactorySupport} creation to {@link #doCreateRepositoryFactory()} and applies the
* {@link TransactionalRepositoryProxyPostProcessor} to the created instance.
*
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport #createRepositoryFactory()
*/
@Override
protected final RepositoryFactorySupport createRepositoryFactory() {
@@ -75,15 +64,13 @@ public abstract class TransactionalRepositoryFactoryBeanSupport<T extends Reposi
return factory;
}
/**
* Creates the actual {@link RepositoryFactorySupport} instance.
*
*
* @return
*/
protected abstract RepositoryFactorySupport doCreateRepositoryFactory();
/*
* (non-Javadoc)
*
@@ -95,9 +82,7 @@ public abstract class TransactionalRepositoryFactoryBeanSupport<T extends Reposi
Assert.isInstanceOf(ListableBeanFactory.class, beanFactory);
this.txPostProcessor =
new TransactionalRepositoryProxyPostProcessor(
(ListableBeanFactory) beanFactory,
transactionManagerName);
this.txPostProcessor = new TransactionalRepositoryProxyPostProcessor((ListableBeanFactory) beanFactory,
transactionManagerName);
}
}

View File

@@ -42,26 +42,22 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
* {@link RepositoryProxyPostProcessor} to add transactional behaviour to
* repository proxies. Adds a {@link PersistenceExceptionTranslationInterceptor}
* as well as an annotation based {@link TransactionInterceptor} to the proxy.
*
* {@link RepositoryProxyPostProcessor} to add transactional behaviour to repository proxies. Adds a
* {@link PersistenceExceptionTranslationInterceptor} as well as an annotation based {@link TransactionInterceptor} to
* the proxy.
*
* @author Oliver Gierke
*/
class TransactionalRepositoryProxyPostProcessor implements
RepositoryProxyPostProcessor {
class TransactionalRepositoryProxyPostProcessor implements RepositoryProxyPostProcessor {
private final TransactionInterceptor transactionInterceptor;
private final PersistenceExceptionTranslationInterceptor petInterceptor;
/**
* Creates a new {@link TransactionalRepositoryProxyPostProcessor}.
*/
public TransactionalRepositoryProxyPostProcessor(
ListableBeanFactory beanFactory, String transactionManagerName) {
public TransactionalRepositoryProxyPostProcessor(ListableBeanFactory beanFactory, String transactionManagerName) {
Assert.notNull(beanFactory);
Assert.notNull(transactionManagerName);
@@ -70,16 +66,12 @@ class TransactionalRepositoryProxyPostProcessor implements
this.petInterceptor.setBeanFactory(beanFactory);
this.petInterceptor.afterPropertiesSet();
this.transactionInterceptor =
new TransactionInterceptor(null,
new CustomAnnotationTransactionAttributeSource());
this.transactionInterceptor
.setTransactionManagerBeanName(transactionManagerName);
this.transactionInterceptor = new TransactionInterceptor(null, new CustomAnnotationTransactionAttributeSource());
this.transactionInterceptor.setTransactionManagerBeanName(transactionManagerName);
this.transactionInterceptor.setBeanFactory(beanFactory);
this.transactionInterceptor.afterPropertiesSet();
}
/*
* (non-Javadoc)
*
@@ -92,7 +84,7 @@ class TransactionalRepositoryProxyPostProcessor implements
factory.addAdvice(petInterceptor);
factory.addAdvice(transactionInterceptor);
}
// The section below contains copies of two core Spring classes that slightly modify the algorithm transaction
// configuration is discovered. The original Spring implementation favours the implementation class' transaction
// configuration over one declared at an interface. As we need to provide the capability to override transaction
@@ -100,21 +92,19 @@ class TransactionalRepositoryProxyPostProcessor implements
// originally invoked method first before digging down into the implementation class.
//
// Unfortunately the Spring classes do not allow modifying this algorithm easily. That's why we have to copy the two
// classes 1:1. Only modifications done are inside
// classes 1:1. Only modifications done are inside
// AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method, Class<?>).
/**
* Implementation of the
* {@link org.springframework.transaction.interceptor.TransactionAttributeSource}
* interface for working with transaction metadata in JDK 1.5+ annotation format.
*
* <p>This class reads Spring's JDK 1.5+ {@link Transactional} annotation and
* exposes corresponding transaction attributes to Spring's transaction infrastructure.
* Also supports EJB3's {@link javax.ejb.TransactionAttribute} annotation (if present).
* This class may also serve as base class for a custom TransactionAttributeSource,
* or get customized through {@link TransactionAnnotationParser} strategies.
*
* Implementation of the {@link org.springframework.transaction.interceptor.TransactionAttributeSource} interface for
* working with transaction metadata in JDK 1.5+ annotation format.
*
* <p>
* This class reads Spring's JDK 1.5+ {@link Transactional} annotation and exposes corresponding transaction
* attributes to Spring's transaction infrastructure. Also supports EJB3's {@link javax.ejb.TransactionAttribute}
* annotation (if present). This class may also serve as base class for a custom TransactionAttributeSource, or get
* customized through {@link TransactionAnnotationParser} strategies.
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @since 1.2
@@ -125,34 +115,31 @@ class TransactionalRepositoryProxyPostProcessor implements
* @see org.springframework.transaction.interceptor.TransactionInterceptor#setTransactionAttributeSource
* @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean#setTransactionAttributeSource
*/
static class CustomAnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
static class CustomAnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource implements
Serializable {
private static final long serialVersionUID = 4841944452113159864L;
private static final boolean ejb3Present = ClassUtils.isPresent(
"javax.ejb.TransactionAttribute", CustomAnnotationTransactionAttributeSource.class.getClassLoader());
private static final long serialVersionUID = 4841944452113159864L;
private static final boolean ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute",
CustomAnnotationTransactionAttributeSource.class.getClassLoader());
private final boolean publicMethodsOnly;
private final Set<TransactionAnnotationParser> annotationParsers;
/**
* Create a default AnnotationTransactionAttributeSource, supporting
* public methods that carry the <code>Transactional</code> annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
* Create a default AnnotationTransactionAttributeSource, supporting public methods that carry the
* <code>Transactional</code> annotation or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
*/
public CustomAnnotationTransactionAttributeSource() {
this(true);
}
/**
* Create a custom AnnotationTransactionAttributeSource, supporting
* public methods that carry the <code>Transactional</code> annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
* @param publicMethodsOnly whether to support public methods that carry
* the <code>Transactional</code> annotation only (typically for use
* with proxy-based AOP), or protected/private methods as well
* (typically used with AspectJ class weaving)
* Create a custom AnnotationTransactionAttributeSource, supporting public methods that carry the
* <code>Transactional</code> annotation or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
*
* @param publicMethodsOnly whether to support public methods that carry the <code>Transactional</code> annotation
* only (typically for use with proxy-based AOP), or protected/private methods as well (typically used with
* AspectJ class weaving)
*/
public CustomAnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
@@ -165,6 +152,7 @@ class TransactionalRepositoryProxyPostProcessor implements
/**
* Create a custom AnnotationTransactionAttributeSource.
*
* @param annotationParser the TransactionAnnotationParser to use
*/
public CustomAnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) {
@@ -175,6 +163,7 @@ class TransactionalRepositoryProxyPostProcessor implements
/**
* Create a custom AnnotationTransactionAttributeSource.
*
* @param annotationParsers the TransactionAnnotationParsers to use
*/
public CustomAnnotationTransactionAttributeSource(Set<TransactionAnnotationParser> annotationParsers) {
@@ -183,7 +172,6 @@ class TransactionalRepositoryProxyPostProcessor implements
this.annotationParsers = annotationParsers;
}
@Override
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
@@ -196,14 +184,15 @@ class TransactionalRepositoryProxyPostProcessor implements
/**
* Determine the transaction attribute for the given method or class.
* <p>This implementation delegates to configured
* {@link TransactionAnnotationParser TransactionAnnotationParsers}
* for parsing known annotations into Spring's metadata attribute class.
* Returns <code>null</code> if it's not transactional.
* <p>Can be overridden to support custom annotations that carry transaction metadata.
* <p>
* This implementation delegates to configured {@link TransactionAnnotationParser TransactionAnnotationParsers} for
* parsing known annotations into Spring's metadata attribute class. Returns <code>null</code> if it's not
* transactional.
* <p>
* Can be overridden to support custom annotations that carry transaction metadata.
*
* @param ae the annotated method or class
* @return TransactionAttribute the configured transaction attribute,
* or <code>null</code> if none was found
* @return TransactionAttribute the configured transaction attribute, or <code>null</code> if none was found
*/
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
@@ -223,23 +212,22 @@ class TransactionalRepositoryProxyPostProcessor implements
return this.publicMethodsOnly;
}
}
/**
* Abstract implementation of {@link TransactionAttributeSource} that caches
* attributes for methods and implements a fallback policy: 1. specific target
* method; 2. target class; 3. declaring method; 4. declaring class/interface.
*
* <p>Defaults to using the target class's transaction attribute if none is
* associated with the target method. Any transaction attribute associated with
* the target method completely overrides a class transaction attribute.
* If none found on the target class, the interface that the invoked method
* has been called through (in case of a JDK proxy) will be checked.
*
* <p>This implementation caches attributes by method after they are first used.
* If it is ever desirable to allow dynamic changing of transaction attributes
* (which is very unlikely), caching could be made configurable. Caching is
* Abstract implementation of {@link TransactionAttributeSource} that caches attributes for methods and implements a
* fallback policy: 1. specific target method; 2. target class; 3. declaring method; 4. declaring class/interface.
*
* <p>
* Defaults to using the target class's transaction attribute if none is associated with the target method. Any
* transaction attribute associated with the target method completely overrides a class transaction attribute. If none
* found on the target class, the interface that the invoked method has been called through (in case of a JDK proxy)
* will be checked.
*
* <p>
* This implementation caches attributes by method after they are first used. If it is ever desirable to allow dynamic
* changing of transaction attributes (which is very unlikely), caching could be made configurable. Caching is
* desirable because of the cost of evaluating rollback rules.
*
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 1.1
@@ -247,34 +235,35 @@ class TransactionalRepositoryProxyPostProcessor implements
abstract static class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {
/**
* Canonical value held in cache to indicate no transaction attribute was
* found for this method, and we don't need to look again.
* Canonical value held in cache to indicate no transaction attribute was found for this method, and we don't need
* to look again.
*/
private final static TransactionAttribute NULL_TRANSACTION_ATTRIBUTE = new DefaultTransactionAttribute();
/**
* Logger available to subclasses.
* <p>As this base class is not marked Serializable, the logger will be recreated
* after serialization - provided that the concrete subclass is Serializable.
* <p>
* As this base class is not marked Serializable, the logger will be recreated after serialization - provided that
* the concrete subclass is Serializable.
*/
protected final Log logger = LogFactory.getLog(getClass());
/**
* Cache of TransactionAttributes, keyed by DefaultCacheKey (Method + target Class).
* <p>As this base class is not marked Serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is Serializable.
* <p>
* As this base class is not marked Serializable, the cache will be recreated after serialization - provided that
* the concrete subclass is Serializable.
*/
final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<Object, TransactionAttribute>();
/**
* Determine the transaction attribute for this method invocation.
* <p>Defaults to the class's transaction attribute if no method attribute is found.
* <p>
* Defaults to the class's transaction attribute if no method attribute is found.
*
* @param method the method for the current invocation (never <code>null</code>)
* @param targetClass the target class for this invocation (may be <code>null</code>)
* @return TransactionAttribute for this method, or <code>null</code> if the method
* is not transactional
* @return TransactionAttribute for this method, or <code>null</code> if the method is not transactional
*/
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
// First, see if we have a cached value.
@@ -285,19 +274,16 @@ class TransactionalRepositoryProxyPostProcessor implements
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
} else {
return (TransactionAttribute) cached;
}
}
else {
} else {
// We need to work it out.
TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAtt == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
} else {
if (logger.isDebugEnabled()) {
logger.debug("Adding transactional method '" + method.getName() + "' with attribute: " + txAtt);
}
@@ -309,8 +295,10 @@ class TransactionalRepositoryProxyPostProcessor implements
/**
* Determine a cache key for the given method and target class.
* <p>Must not produce same key for overloaded methods.
* Must produce same key for different instances of the same method.
* <p>
* Must not produce same key for overloaded methods. Must produce same key for different instances of the same
* method.
*
* @param method the method (never <code>null</code>)
* @param targetClass the target class (may be <code>null</code>)
* @return the cache key (never <code>null</code>)
@@ -322,6 +310,7 @@ class TransactionalRepositoryProxyPostProcessor implements
/**
* Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
* {@link #getTransactionAttribute} is effectively a caching decorator for this method.
*
* @see #getTransactionAttribute
*/
private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
@@ -337,7 +326,7 @@ class TransactionalRepositoryProxyPostProcessor implements
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
TransactionAttribute txAtt = null;
if (specificMethod != method) {
@@ -348,13 +337,13 @@ class TransactionalRepositoryProxyPostProcessor implements
}
// Last fallback is the class of the original method.
txAtt = findTransactionAttribute(method.getDeclaringClass());
if (txAtt != null) {
return txAtt;
}
}
// Start: Implementation class check block
// Start: Implementation class check block
// First try is the method in the target class.
txAtt = findTransactionAttribute(specificMethod);
@@ -367,40 +356,36 @@ class TransactionalRepositoryProxyPostProcessor implements
if (txAtt != null) {
return txAtt;
}
// End: Implementation class check block
return null;
}
/**
* Subclasses need to implement this to return the transaction attribute
* for the given method, if any.
* Subclasses need to implement this to return the transaction attribute for the given method, if any.
*
* @param method the method to retrieve the attribute for
* @return all transaction attribute associated with this method
* (or <code>null</code> if none)
* @return all transaction attribute associated with this method (or <code>null</code> if none)
*/
protected abstract TransactionAttribute findTransactionAttribute(Method method);
/**
* Subclasses need to implement this to return the transaction attribute
* for the given class, if any.
* Subclasses need to implement this to return the transaction attribute for the given class, if any.
*
* @param clazz the class to retrieve the attribute for
* @return all transaction attribute associated with this class
* (or <code>null</code> if none)
* @return all transaction attribute associated with this class (or <code>null</code> if none)
*/
protected abstract TransactionAttribute findTransactionAttribute(Class<?> clazz);
/**
* Should only public methods be allowed to have transactional semantics?
* <p>The default implementation returns <code>false</code>.
* <p>
* The default implementation returns <code>false</code>.
*/
protected boolean allowPublicMethodsOnly() {
return false;
}
/**
* Default cache key for the TransactionAttribute cache.
*/
@@ -424,8 +409,8 @@ class TransactionalRepositoryProxyPostProcessor implements
return false;
}
DefaultCacheKey otherKey = (DefaultCacheKey) other;
return (this.method.equals(otherKey.method) &&
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
return (this.method.equals(otherKey.method) && ObjectUtils.nullSafeEquals(this.targetClass,
otherKey.targetClass));
}
@Override

View File

@@ -21,11 +21,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to bind let method parameters be bound to a query via a named
* parameter.
*
* Annotation to bind let method parameters be bound to a query via a named parameter.
*
* @author Oliver Gierke
*/
@Target(ElementType.PARAMETER)

View File

@@ -26,23 +26,18 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
/**
* Class to abstract a single parameter of a query method. It is held in the
* context of a {@link Parameters} instance.
*
* Class to abstract a single parameter of a query method. It is held in the context of a {@link Parameters} instance.
*
* @author Oliver Gierke
*/
public class Parameter {
@SuppressWarnings("unchecked")
static final List<Class<?>> TYPES = Arrays.asList(Pageable.class,
Sort.class);
static final List<Class<?>> TYPES = Arrays.asList(Pageable.class, Sort.class);
private static final String PARAM_ON_SPECIAL = format(
"You must not user @%s on a parameter typed %s or %s",
Param.class.getSimpleName(), Pageable.class.getSimpleName(),
Sort.class.getSimpleName());
private static final String PARAM_ON_SPECIAL = format("You must not user @%s on a parameter typed %s or %s",
Param.class.getSimpleName(), Pageable.class.getSimpleName(), Sort.class.getSimpleName());
private static final String NAMED_PARAMETER_TEMPLATE = ":%s";
private static final String POSITION_PARAMETER_TEMPLATE = "?%s";
@@ -50,9 +45,9 @@ public class Parameter {
private final MethodParameter parameter;
/**
* Creates a new {@link Parameter} for the given type, {@link Annotation}s,
* positioned at the given index inside the given {@link Parameters}.
*
* Creates a new {@link Parameter} for the given type, {@link Annotation}s, positioned at the given index inside the
* given {@link Parameters}.
*
* @param type
* @param parameters
* @param index
@@ -69,10 +64,9 @@ public class Parameter {
}
}
/**
* Returns whether the {@link Parameter} is the first one.
*
*
* @return
*/
boolean isFirst() {
@@ -80,10 +74,9 @@ public class Parameter {
return getIndex() == 0;
}
/**
* Returns whether the parameter is a special parameter.
*
*
* @param index
* @return
* @see #TYPES
@@ -93,10 +86,9 @@ public class Parameter {
return TYPES.contains(parameter.getParameterType());
}
/**
* Returns whether the {@link Parameter} is to be bound to a query.
*
*
* @return
*/
public boolean isBindable() {
@@ -104,11 +96,9 @@ public class Parameter {
return !isSpecialParameter();
}
/**
* Returns the placeholder to be used for the parameter. Can either be a
* named one or positional.
*
* Returns the placeholder to be used for the parameter. Can either be a named one or positional.
*
* @param index
* @return
*/
@@ -121,11 +111,9 @@ public class Parameter {
}
}
/**
* Returns the position index the parameter is bound to in the context of
* its surrounding {@link Parameters}.
*
* Returns the position index the parameter is bound to in the context of its surrounding {@link Parameters}.
*
* @return
*/
public int getIndex() {
@@ -133,10 +121,9 @@ public class Parameter {
return parameter.getParameterIndex();
}
/**
* Returns whether the parameter is annotated with {@link Param}.
*
*
* @param index
* @return
*/
@@ -145,11 +132,9 @@ public class Parameter {
return !isSpecialParameter() && getName() != null;
}
/**
* Returns the name of the parameter (through {@link Param} annotation) or
* null if none can be found.
*
* Returns the name of the parameter (through {@link Param} annotation) or null if none can be found.
*
* @return
*/
public String getName() {
@@ -157,7 +142,6 @@ public class Parameter {
return annotation == null ? parameter.getParameterName() : annotation.value();
}
/**
* Returns the type of the {@link Parameter}.
*
@@ -166,7 +150,7 @@ public class Parameter {
public Class<?> getType() {
return parameter.getParameterType();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
@@ -174,14 +158,12 @@ public class Parameter {
@Override
public String toString() {
return format("%s:%s", isNamedParameter() ? getName() : "#" + getIndex(),
getType().getName());
return format("%s:%s", isNamedParameter() ? getName() : "#" + getIndex(), getType().getName());
}
/**
* Returns whether the {@link Parameter} is a {@link Pageable} parameter.
*
*
* @return
*/
boolean isPageable() {
@@ -189,10 +171,9 @@ public class Parameter {
return Pageable.class.isAssignableFrom(getType());
}
/**
* Returns whether the {@link Parameter} is a {@link Sort} parameter.
*
*
* @return
*/
boolean isSort() {

View File

@@ -20,53 +20,42 @@ import java.util.Iterator;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
/**
* Interface to access method parameters. Allows dedicated access to parameters
* of special types
*
* Interface to access method parameters. Allows dedicated access to parameters of special types
*
* @author Oliver Gierke
*/
public interface ParameterAccessor extends Iterable<Object> {
/**
* Returns the {@link Pageable} of the parameters, if available. Returns
* {@code null} otherwise.
*
* Returns the {@link Pageable} of the parameters, if available. Returns {@code null} otherwise.
*
* @return
*/
Pageable getPageable();
/**
* Returns the sort instance to be used for query creation. Will use a
* {@link Sort} parameter if available or the {@link Sort} contained in a
* {@link Pageable} if available. Returns {@code null} if no {@link Sort}
* can be found.
*
* Returns the sort instance to be used for query creation. Will use a {@link Sort} parameter if available or the
* {@link Sort} contained in a {@link Pageable} if available. Returns {@code null} if no {@link Sort} can be found.
*
* @return
*/
Sort getSort();
/**
* Returns the bindable value with the given index. Bindable means, that
* {@link Pageable} and {@link Sort} values are skipped without noticed in
* the index. For a method signature taking {@link String}, {@link Pageable}
* , {@link String}, {@code #getBindableParameter(1)} would return the
* second {@link String} value.
*
* Returns the bindable value with the given index. Bindable means, that {@link Pageable} and {@link Sort} values are
* skipped without noticed in the index. For a method signature taking {@link String}, {@link Pageable} ,
* {@link String}, {@code #getBindableParameter(1)} would return the second {@link String} value.
*
* @param index
* @return
*/
Object getBindableValue(int index);
/**
* Returns an iterator over all <em>bindable</em> parameters. This means
* parameters implementing {@link Pageable} or {@link Sort} will not be
* included in this {@link Iterator}.
*
* Returns an iterator over all <em>bindable</em> parameters. This means parameters implementing {@link Pageable} or
* {@link Sort} will not be included in this {@link Iterator}.
*
* @return
*/
Iterator<Object> iterator();

View File

@@ -16,20 +16,18 @@
package org.springframework.data.repository.query;
/**
* Exception to be thrown when trying to access a {@link Parameter} with an
* invalid index inside a {@link Parameters} instance.
*
* Exception to be thrown when trying to access a {@link Parameter} with an invalid index inside a {@link Parameters}
* instance.
*
* @author Oliver Gierke
*/
public class ParameterOutOfBoundsException extends RuntimeException {
private static final long serialVersionUID = 8433209953653278886L;
/**
* Creates a new {@link ParameterOutOfBoundsException} with the given
* exception as cause.
*
* Creates a new {@link ParameterOutOfBoundsException} with the given exception as cause.
*
* @param cause
*/
public ParameterOutOfBoundsException(Throwable cause) {

View File

@@ -28,37 +28,29 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
/**
* Abstracts method parameters that have to be bound to query parameters or
* applied to the query independently.
*
* Abstracts method parameters that have to be bound to query parameters or applied to the query independently.
*
* @author Oliver Gierke
*/
public class Parameters implements Iterable<Parameter> {
@SuppressWarnings("unchecked")
public static final List<Class<?>> TYPES = Arrays.asList(Pageable.class,
Sort.class);
public static final List<Class<?>> TYPES = Arrays.asList(Pageable.class, Sort.class);
private static final String ALL_OR_NOTHING =
String.format(
"Either use @%s "
+ "on all parameters except %s and %s typed once, or none at all!",
Param.class.getSimpleName(),
Pageable.class.getSimpleName(), Sort.class.getSimpleName());
private static final String ALL_OR_NOTHING = String.format("Either use @%s "
+ "on all parameters except %s and %s typed once, or none at all!", Param.class.getSimpleName(),
Pageable.class.getSimpleName(), Sort.class.getSimpleName());
private final int pageableIndex;
private final int sortIndex;
private final List<Parameter> parameters;
private final ParameterNameDiscoverer discoverer =
new LocalVariableTableParameterNameDiscoverer();
private final ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
/**
* Creates a new instance of {@link Parameters}.
*
*
* @param method
*/
public Parameters(Method method) {
@@ -81,11 +73,9 @@ public class Parameters implements Iterable<Parameter> {
assertEitherAllParamAnnotatedOrNone();
}
/**
* Creates a new {@link Parameters} instance with the given
* {@link Parameter}s put into new context.
*
* Creates a new {@link Parameters} instance with the given {@link Parameter}s put into new context.
*
* @param originals
*/
private Parameters(List<Parameter> originals) {
@@ -107,16 +97,14 @@ public class Parameters implements Iterable<Parameter> {
this.pageableIndex = pageableIndexTemp;
this.sortIndex = sortIndexTemp;
}
protected Parameter createParameter(MethodParameter parameter) {
return new Parameter(parameter);
}
/**
* Returns whether the method the {@link Parameters} was created for
* contains a {@link Pageable} argument.
*
* Returns whether the method the {@link Parameters} was created for contains a {@link Pageable} argument.
*
* @return
*/
public boolean hasPageableParameter() {
@@ -124,12 +112,10 @@ public class Parameters implements Iterable<Parameter> {
return pageableIndex != -1;
}
/**
* Returns the index of the {@link Pageable} {@link Method} parameter if
* available. Will return {@literal -1} if there is no {@link Pageable}
* argument in the {@link Method}'s parameter list.
*
* Returns the index of the {@link Pageable} {@link Method} parameter if available. Will return {@literal -1} if there
* is no {@link Pageable} argument in the {@link Method}'s parameter list.
*
* @return the pageableIndex
*/
public int getPageableIndex() {
@@ -137,12 +123,10 @@ public class Parameters implements Iterable<Parameter> {
return pageableIndex;
}
/**
* Returns the index of the {@link Sort} {@link Method} parameter if
* available. Will return {@literal -1} if there is no {@link Sort} argument
* in the {@link Method}'s parameter list.
*
* Returns the index of the {@link Sort} {@link Method} parameter if available. Will return {@literal -1} if there is
* no {@link Sort} argument in the {@link Method}'s parameter list.
*
* @return
*/
public int getSortIndex() {
@@ -150,33 +134,29 @@ public class Parameters implements Iterable<Parameter> {
return sortIndex;
}
/**
* Returns whether the method the {@link Parameters} was created for
* contains a {@link Sort} argument.
*
* Returns whether the method the {@link Parameters} was created for contains a {@link Sort} argument.
*
* @return
*/
public boolean hasSortParameter() {
return sortIndex != -1;
}
/**
* Returns whether we potentially find a {@link Sort} parameter in the parameters.
*
* @return
*/
public boolean potentiallySortsDynamically() {
return hasSortParameter() || hasPageableParameter();
}
/**
* Returns the parameter with the given index.
*
*
* @param index
* @return
*/
@@ -189,10 +169,9 @@ public class Parameters implements Iterable<Parameter> {
}
}
/**
* Returns whether we have a parameter at the given position.
*
*
* @param position
* @return
*/
@@ -205,11 +184,9 @@ public class Parameters implements Iterable<Parameter> {
}
}
/**
* Returns whether the method signature contains one of the special
* parameters ({@link Pageable}, {@link Sort}).
*
* Returns whether the method signature contains one of the special parameters ({@link Pageable}, {@link Sort}).
*
* @return
*/
public boolean hasSpecialParameter() {
@@ -217,10 +194,9 @@ public class Parameters implements Iterable<Parameter> {
return hasSortParameter() || hasPageableParameter();
}
/**
* Returns the number of parameters.
*
*
* @return
*/
public int getNumberOfParameters() {
@@ -228,11 +204,9 @@ public class Parameters implements Iterable<Parameter> {
return parameters.size();
}
/**
* Returns a {@link Parameters} instance with effectively all special
* parameters removed.
*
* Returns a {@link Parameters} instance with effectively all special parameters removed.
*
* @return
* @see Parameter#TYPES
* @see Parameter#isSpecialParameter()
@@ -251,13 +225,11 @@ public class Parameters implements Iterable<Parameter> {
return new Parameters(bindables);
}
/**
* Returns a bindable parameter with the given index. So for a method with a
* signature of {@code (Pageable pageable, String name)} a call to
* {@code #getBindableParameter(0)} will return the {@link String}
* Returns a bindable parameter with the given index. So for a method with a signature of
* {@code (Pageable pageable, String name)} a call to {@code #getBindableParameter(0)} will return the {@link String}
* parameter.
*
*
* @param bindableIndex
* @return
*/
@@ -266,11 +238,10 @@ public class Parameters implements Iterable<Parameter> {
return getBindableParameters().getParameter(bindableIndex);
}
/**
* Asserts that either all of the non special parameters ({@link Pageable},
* {@link Sort}) are annotated with {@link Param} or none of them is.
*
* Asserts that either all of the non special parameters ({@link Pageable}, {@link Sort}) are annotated with
* {@link Param} or none of them is.
*
* @param method
*/
private void assertEitherAllParamAnnotatedOrNone() {
@@ -288,10 +259,9 @@ public class Parameters implements Iterable<Parameter> {
}
}
/**
* Returns whether the given type is a bindable parameter.
*
*
* @param type
* @return
*/
@@ -300,7 +270,6 @@ public class Parameters implements Iterable<Parameter> {
return !TYPES.contains(type);
}
/*
* (non-Javadoc)
*

View File

@@ -21,11 +21,9 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
/**
* {@link ParameterAccessor} implementation using a {@link Parameters} instance
* to find special parameters.
*
* {@link ParameterAccessor} implementation using a {@link Parameters} instance to find special parameters.
*
* @author Oliver Gierke
*/
public class ParametersParameterAccessor implements ParameterAccessor {
@@ -33,10 +31,9 @@ public class ParametersParameterAccessor implements ParameterAccessor {
private final Parameters parameters;
private final Object[] values;
/**
* Creates a new {@link ParametersParameterAccessor}.
*
*
* @param parameters
* @param values
*/
@@ -45,14 +42,12 @@ public class ParametersParameterAccessor implements ParameterAccessor {
Assert.notNull(parameters);
Assert.notNull(values);
Assert.isTrue(parameters.getNumberOfParameters() == values.length,
"Invalid number of parameters given!");
Assert.isTrue(parameters.getNumberOfParameters() == values.length, "Invalid number of parameters given!");
this.parameters = parameters;
this.values = values.clone();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.ParameterAccessor#getPageable()
@@ -66,7 +61,6 @@ public class ParametersParameterAccessor implements ParameterAccessor {
return (Pageable) values[parameters.getPageableIndex()];
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.ParameterAccessor#getSort()
@@ -83,7 +77,7 @@ public class ParametersParameterAccessor implements ParameterAccessor {
return null;
}
/**
* Returns the value with the given index.
*
@@ -95,7 +89,6 @@ public class ParametersParameterAccessor implements ParameterAccessor {
return (T) values[index];
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.ParameterAccessor#getBindableValue(int)
@@ -105,7 +98,6 @@ public class ParametersParameterAccessor implements ParameterAccessor {
return values[parameters.getBindableParameter(index).getIndex()];
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.ParameterAccessor#iterator()
@@ -116,19 +108,17 @@ public class ParametersParameterAccessor implements ParameterAccessor {
}
/**
* Iterator class to allow traversing all bindable parameters inside the
* accessor.
*
* Iterator class to allow traversing all bindable parameters inside the accessor.
*
* @author Oliver Gierke
*/
private class BindableParameterIterator implements Iterator<Object> {
private int currentIndex = 0;
/**
* Returns the next bindable parameter.
*
*
* @return
*/
public Object next() {
@@ -136,7 +126,6 @@ public class ParametersParameterAccessor implements ParameterAccessor {
return getBindableValue(currentIndex++);
}
/*
* (non-Javadoc)
* @see java.util.Iterator#hasNext()
@@ -146,7 +135,6 @@ public class ParametersParameterAccessor implements ParameterAccessor {
return values.length > currentIndex;
}
/*
* (non-Javadoc)
* @see java.util.Iterator#remove()

View File

@@ -16,21 +16,18 @@
package org.springframework.data.repository.query;
/**
* Exception to be thrown if a query cannot be created from a
* {@link QueryMethod}.
*
* Exception to be thrown if a query cannot be created from a {@link QueryMethod}.
*
* @author Oliver Gierke
*/
public final class QueryCreationException extends RuntimeException {
private static final long serialVersionUID = -1238456123580L;
private static final String MESSAGE_TEMPLATE =
"Could not create query for method %s! Could not find property %s on domain class %s.";
private static final String MESSAGE_TEMPLATE = "Could not create query for method %s! Could not find property %s on domain class %s.";
/**
* Creates a new {@link QueryCreationException}.
*
*
* @param method
*/
private QueryCreationException(String message) {
@@ -38,47 +35,39 @@ public final class QueryCreationException extends RuntimeException {
super(message);
}
/**
* Rejects the given domain class property.
*
*
* @param method
* @param propertyName
* @return
*/
public static QueryCreationException invalidProperty(QueryMethod method,
String propertyName) {
public static QueryCreationException invalidProperty(QueryMethod method, String propertyName) {
return new QueryCreationException(String.format(MESSAGE_TEMPLATE,
method, propertyName, method.getDomainClass().getName()));
return new QueryCreationException(String.format(MESSAGE_TEMPLATE, method, propertyName, method.getDomainClass()
.getName()));
}
/**
* Creates a new {@link QueryCreationException}.
*
*
* @param method
* @param message
* @return
*/
public static QueryCreationException create(QueryMethod method,
String message) {
public static QueryCreationException create(QueryMethod method, String message) {
return new QueryCreationException(String.format(
"Could not create query for %s! Reason: %s", method, message));
return new QueryCreationException(String.format("Could not create query for %s! Reason: %s", method, message));
}
/**
* Creates a new {@link QueryCreationException} for the given
* {@link QueryMethod} and {@link Throwable} as cause.
*
* Creates a new {@link QueryCreationException} for the given {@link QueryMethod} and {@link Throwable} as cause.
*
* @param method
* @param cause
* @return
*/
public static QueryCreationException create(QueryMethod method,
Throwable cause) {
public static QueryCreationException create(QueryMethod method, Throwable cause) {
return create(method, cause.getMessage());
}

View File

@@ -22,10 +22,9 @@ import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.util.StringUtils;
/**
* Strategy interface for which way to lookup {@link RepositoryQuery}s.
*
*
* @author Oliver Gierke
*/
public interface QueryLookupStrategy {
@@ -36,7 +35,7 @@ public interface QueryLookupStrategy {
/**
* Returns a strategy key from the given XML value.
*
*
* @param xml
* @return a strategy key from the given XML value
*/
@@ -50,11 +49,9 @@ public interface QueryLookupStrategy {
}
}
/**
* Resolves a {@link RepositoryQuery} from the given {@link QueryMethod}
* that can be executed afterwards.
*
* Resolves a {@link RepositoryQuery} from the given {@link QueryMethod} that can be executed afterwards.
*
* @param method
* @param metadata
* @param namedQueries

View File

@@ -28,12 +28,10 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.util.ClassUtils;
import org.springframework.util.Assert;
/**
* Abstraction of a method that is designated to execute a finder query.
* Enriches the standard {@link Method} interface with specific information that
* is necessary to construct {@link RepositoryQuery}s for the method.
*
* Abstraction of a method that is designated to execute a finder query. Enriches the standard {@link Method} interface
* with specific information that is necessary to construct {@link RepositoryQuery}s for the method.
*
* @author Oliver Gierke
*/
public class QueryMethod {
@@ -42,11 +40,10 @@ public class QueryMethod {
private final Method method;
private final Parameters parameters;
/**
* Creates a new {@link QueryMethod} from the given parameters. Looks up the
* correct query to use for following invocations of the method given.
*
* Creates a new {@link QueryMethod} from the given parameters. Looks up the correct query to use for following
* invocations of the method given.
*
* @param method must not be {@literal null}
* @param metadata must not be {@literal null}
*/
@@ -57,46 +54,43 @@ public class QueryMethod {
for (Class<?> type : Parameters.TYPES) {
if (getNumberOfOccurences(method, type) > 1) {
throw new IllegalStateException(String.format(
"Method must only one argument of type %s!",
type.getSimpleName()));
throw new IllegalStateException(
String.format("Method must only one argument of type %s!", type.getSimpleName()));
}
}
if (hasParameterOfType(method, Pageable.class)) {
assertReturnTypeAssignable(method, Page.class, List.class);
if (hasParameterOfType(method, Sort.class)) {
throw new IllegalStateException(
"Method must not have Pageable *and* Sort parameter. "
+ "Use sorting capabilities on Pageble instead!");
throw new IllegalStateException("Method must not have Pageable *and* Sort parameter. "
+ "Use sorting capabilities on Pageble instead!");
}
}
this.method = method;
this.parameters = createParameters(method);
this.metadata = metadata;
Assert.notNull(this.parameters);
if (isPageQuery()) {
Assert.isTrue(this.parameters.hasPageableParameter(), "Paging query needs to have a Pageable parameter!");
}
}
/**
* Creates a {@link Parameters} instance.
*
* @param method
* @return must not return {@literal null}.
* @return must not return {@literal null}.
*/
protected Parameters createParameters(Method method) {
return new Parameters(method);
}
/**
* Returns the method's name.
*
*
* @return
*/
public String getName() {
@@ -104,7 +98,6 @@ public class QueryMethod {
return method.getName();
}
@SuppressWarnings("rawtypes")
public EntityMetadata<?> getEntityInformation() {
@@ -117,19 +110,16 @@ public class QueryMethod {
};
}
/**
* Returns the name of the named query this method belongs to.
*
* @return
*/
public String getNamedQueryName() {
/**
* 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());
}
Class<?> domainClass = getDomainClass();
return String.format("%s.%s", domainClass.getSimpleName(), method.getName());
}
protected Class<?> getDomainClass() {
@@ -140,11 +130,9 @@ public class QueryMethod {
: repositoryDomainClass;
}
/**
* Returns whether the finder will actually return a collection of entities
* or a single one.
*
* Returns whether the finder will actually return a collection of entities or a single one.
*
* @return
*/
public boolean isCollectionQuery() {
@@ -153,30 +141,25 @@ public class QueryMethod {
return !isPageQuery() && org.springframework.util.ClassUtils.isAssignable(Iterable.class, returnType);
}
/**
* Returns whether the finder will return a {@link Page} of results.
*
*
* @return
*/
public boolean isPageQuery() {
Class<?> returnType = method.getReturnType();
return org.springframework.util.ClassUtils.isAssignable(Page.class,
returnType);
return org.springframework.util.ClassUtils.isAssignable(Page.class, returnType);
}
public boolean isModifyingQuery() {
return false;
}
/**
* Returns the {@link Parameters} wrapper to gain additional information
* about {@link Method} parameters.
*
* Returns the {@link Parameters} wrapper to gain additional information about {@link Method} parameters.
*
* @return
*/
public Parameters getParameters() {
@@ -184,7 +167,6 @@ public class QueryMethod {
return parameters;
}
/*
* (non-Javadoc)
*

View File

@@ -15,28 +15,25 @@
*/
package org.springframework.data.repository.query;
/**
* Interface for a query abstraction.
*
*
* @author Oliver Gierke
*/
public interface RepositoryQuery {
/**
* Executes the {@link RepositoryQuery} with the given parameters.
*
*
* @param store
* @param parameters
* @return
*/
public Object execute(Object[] parameters);
/**
* Returns the
*
*
* @return
*/
public QueryMethod getQueryMethod();

View File

@@ -72,7 +72,7 @@ public abstract class AbstractQueryCreator<T, S> {
Sort dynamicSort = parameters != null ? parameters.getSort() : null;
return createQuery(dynamicSort);
}
/**
* Creates the actual query object applying the given {@link Sort} parameter. Use this method in case you haven't
* provided a {@link ParameterAccessor} in the first place but want to apply dynamic sorting nevertheless.
@@ -81,10 +81,10 @@ public abstract class AbstractQueryCreator<T, S> {
* @return
*/
public T createQuery(Sort dynamicSort) {
Sort staticSort = tree.getSort();
Sort sort = staticSort != null ? staticSort.and(dynamicSort) : dynamicSort;
return complete(createCriteria(tree), sort);
}

View File

@@ -213,11 +213,11 @@ public class PartTree implements Iterable<OrPart> {
predicate = detectAndSetAllIgnoreCase(predicate);
String[] parts = split(predicate, ORDER_BY);
if (parts.length > 2) {
throw new IllegalArgumentException("OrderBy must not be used more than once in a method name!");
}
buildTree(parts[0], domainClass);
this.orderBySource = parts.length == 2 ? new OrderBySource(parts[1], domainClass) : null;
}
@@ -225,12 +225,12 @@ public class PartTree implements Iterable<OrPart> {
private String detectAndSetAllIgnoreCase(String predicate) {
Matcher matcher = ALL_IGNORE_CASE.matcher(predicate);
if (matcher.find()) {
alwaysIgnoreCase = true;
predicate = predicate.substring(0, matcher.start()) + predicate.substring(matcher.end(), predicate.length());
}
return predicate;
}

View File

@@ -26,14 +26,13 @@ import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Abstraction of a {@link Property} of a domain class.
*
*
* @author Oliver Gierke
*/
public class Property {
private static final String DELIMITERS = "_\\.";
private static final Pattern SPLITTER = Pattern.compile("(?:[%s]?([%s]*?[^%s]+))".replaceAll("%s", DELIMITERS));
private static final String ERROR_TEMPLATE = "No property %s found for type %s";
@@ -45,11 +44,9 @@ public class Property {
private Property next;
/**
* Creates a leaf {@link Property} (no nested ones) with the given name inside the
* given owning type.
*
* Creates a leaf {@link Property} (no nested ones) with the given name inside the given owning type.
*
* @param name
* @param owningType
*/
@@ -73,8 +70,7 @@ public class Property {
TypeInformation<?> type = owningType.getProperty(propertyName);
if (type == null) {
throw new IllegalArgumentException(String.format(ERROR_TEMPLATE,
propertyName, owningType.getType()));
throw new IllegalArgumentException(String.format(ERROR_TEMPLATE, propertyName, owningType.getType()));
}
this.owningType = owningType;
@@ -84,10 +80,9 @@ public class Property {
}
/**
* Creates a {@link Property} with the given name inside the given owning
* type and tries to resolve the other {@link String} to create nested
* properties.
*
* Creates a {@link Property} with the given name inside the given owning type and tries to resolve the other
* {@link String} to create nested properties.
*
* @param name
* @param owningType
* @param toTraverse
@@ -112,7 +107,7 @@ public class Property {
/**
* Returns the name of the {@link Property}.
*
*
* @return the name will never be {@literal null}.
*/
public String getName() {
@@ -121,10 +116,9 @@ public class Property {
}
/**
* Returns the type of the property will return the plain resolved type for
* simple properties, the component type for any {@link Iterable} or the
* value type of a {@link java.util.Map} if the property is one.
*
* Returns the type of the property will return the plain resolved type for simple properties, the component type for
* any {@link Iterable} or the value type of a {@link java.util.Map} if the property is one.
*
* @return
*/
public Class<?> getType() {
@@ -132,12 +126,10 @@ public class Property {
return this.type.getType();
}
/**
* Returns the next nested {@link Property}.
*
* @return the next nested {@link Property} or {@literal null} if no nested
* {@link Property} available.
*
* @return the next nested {@link Property} or {@literal null} if no nested {@link Property} available.
* @see #hasNext()
*/
public Property next() {
@@ -145,12 +137,10 @@ public class Property {
return next;
}
/**
* Returns whether there is a nested {@link Property}. If this returns
* {@literal true} you can expect {@link #next()} to return a non-
* {@literal null} value.
*
* Returns whether there is a nested {@link Property}. If this returns {@literal true} you can expect {@link #next()}
* to return a non- {@literal null} value.
*
* @return
*/
public boolean hasNext() {
@@ -158,10 +148,9 @@ public class Property {
return next != null;
}
/**
* Returns the {@link Property} path in dot notation.
*
*
* @return
*/
public String toDotPath() {
@@ -173,10 +162,9 @@ public class Property {
return getName();
}
/**
* Returns whether the {@link Property} is actually a collection.
*
*
* @return
*/
public boolean isCollection() {
@@ -184,7 +172,6 @@ public class Property {
return isCollection;
}
/*
* (non-Javadoc)
*
@@ -206,7 +193,6 @@ public class Property {
return this.name.equals(that.name) && this.type.equals(type);
}
/*
* (non-Javadoc)
*
@@ -218,11 +204,9 @@ public class Property {
return name.hashCode() + type.hashCode();
}
/**
* Extracts the {@link Property} chain from the given source {@link String}
* and type.
*
* Extracts the {@link Property} chain from the given source {@link String} and type.
*
* @param source
* @param type
* @return
@@ -233,10 +217,10 @@ public class Property {
}
private static Property from(String source, TypeInformation<?> type) {
List<String> iteratorSource = new ArrayList<String>();
Matcher matcher = SPLITTER.matcher("_" + source);
while (matcher.find()) {
iteratorSource.add(matcher.group(1));
}
@@ -258,11 +242,9 @@ public class Property {
return result;
}
/**
* Creates a new {@link Property} as subordinary of the given
* {@link Property}.
*
* Creates a new {@link Property} as subordinary of the given {@link Property}.
*
* @param source
* @param base
* @return
@@ -274,15 +256,12 @@ public class Property {
return property;
}
/**
* Factory method to create a new {@link Property} for the given
* {@link String} and owning type. It will inspect the given source for
* camel-case parts and traverse the {@link String} along its parts starting
* with the entire one and chewing off parts from the right side then.
* Whenever a valid property for the given class is found, the tail will be
* traversed for subordinary properties of the just found one and so on.
*
* Factory method to create a new {@link Property} for the given {@link String} and owning type. It will inspect the
* given source for camel-case parts and traverse the {@link String} along its parts starting with the entire one and
* chewing off parts from the right side then. Whenever a valid property for the given class is found, the tail will
* be traversed for subordinary properties of the just found one and so on.
*
* @param source
* @param type
* @return
@@ -292,13 +271,11 @@ public class Property {
return create(source, type, "");
}
/**
* Tries to look up a chain of {@link Property}s by trying the givne source
* first. If that fails it will split the source apart at camel case borders
* (starting from the right side) and try to look up a {@link Property} from
* the calculated head and recombined new tail and additional tail.
*
* Tries to look up a chain of {@link Property}s by trying the givne source first. If that fails it will split the
* source apart at camel case borders (starting from the right side) and try to look up a {@link Property} from the
* calculated head and recombined new tail and additional tail.
*
* @param source
* @param type
* @param addTail

View File

@@ -32,27 +32,22 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.support.RepositoryFactoryInformation;
/**
* {@link org.springframework.core.convert.converter.Converter} to convert
* arbitrary input into domain classes managed by Spring Data {@link CrudRepository}
* s. The implementation uses a {@link ConversionService} in turn to convert the
* source type into the domain class' id type which is then converted into a
* domain class object by using a {@link CrudRepository}.
*
* {@link org.springframework.core.convert.converter.Converter} to convert arbitrary input into domain classes managed
* by Spring Data {@link CrudRepository} s. The implementation uses a {@link ConversionService} in turn to convert the
* source type into the domain class' id type which is then converted into a domain class object by using a
* {@link CrudRepository}.
*
* @author Oliver Gierke
*/
public class DomainClassConverter implements ConditionalGenericConverter,
ApplicationContextAware {
public class DomainClassConverter implements ConditionalGenericConverter, ApplicationContextAware {
private final Map<EntityInformation<?, Serializable>, CrudRepository<?, Serializable>> repositories =
new HashMap<EntityInformation<?, Serializable>, CrudRepository<?, Serializable>>();
private final Map<EntityInformation<?, Serializable>, CrudRepository<?, Serializable>> repositories = new HashMap<EntityInformation<?, Serializable>, CrudRepository<?, Serializable>>();
private final ConversionService service;
/**
* Creates a new {@link DomainClassConverter}.
*
*
* @param service
*/
public DomainClassConverter(ConversionService service) {
@@ -60,7 +55,6 @@ public class DomainClassConverter implements ConditionalGenericConverter,
this.service = service;
}
/*
* (non-Javadoc)
*
@@ -69,11 +63,9 @@ public class DomainClassConverter implements ConditionalGenericConverter,
*/
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(Object.class,
Object.class));
return Collections.singleton(new ConvertiblePair(Object.class, Object.class));
}
/*
* (non-Javadoc)
*
@@ -82,18 +74,15 @@ public class DomainClassConverter implements ConditionalGenericConverter,
* .lang.Object, org.springframework.core.convert.TypeDescriptor,
* org.springframework.core.convert.TypeDescriptor)
*/
public Object convert(Object source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
EntityInformation<?, Serializable> info =
getRepositoryForDomainType(targetType.getType());
EntityInformation<?, Serializable> info = getRepositoryForDomainType(targetType.getType());
CrudRepository<?, Serializable> repository = repositories.get(info);
Serializable id = service.convert(source, info.getIdType());
return repository.findOne(id);
}
/*
* (non-Javadoc)
*
@@ -104,8 +93,7 @@ public class DomainClassConverter implements ConditionalGenericConverter,
*/
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
EntityInformation<?, ?> info =
getRepositoryForDomainType(targetType.getType());
EntityInformation<?, ?> info = getRepositoryForDomainType(targetType.getType());
if (info == null) {
return false;
@@ -114,12 +102,9 @@ public class DomainClassConverter implements ConditionalGenericConverter,
return service.canConvert(sourceType.getType(), info.getIdType());
}
private EntityInformation<?, Serializable> getRepositoryForDomainType(Class<?> domainType) {
private EntityInformation<?, Serializable> getRepositoryForDomainType(
Class<?> domainType) {
for (EntityInformation<?, Serializable> information : repositories
.keySet()) {
for (EntityInformation<?, Serializable> information : repositories.keySet()) {
if (domainType.equals(information.getJavaType())) {
return information;
@@ -129,7 +114,6 @@ public class DomainClassConverter implements ConditionalGenericConverter,
return null;
}
/*
* (non-Javadoc)
*
@@ -137,21 +121,17 @@ public class DomainClassConverter implements ConditionalGenericConverter,
* org.springframework.context.ApplicationContextAware#setApplicationContext
* (org.springframework.context.ApplicationContext)
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({ "unchecked", "rawtypes" })
public void setApplicationContext(ApplicationContext context) {
Collection<RepositoryFactoryInformation> providers =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context,
RepositoryFactoryInformation.class).values();
Collection<RepositoryFactoryInformation> providers = BeanFactoryUtils.beansOfTypeIncludingAncestors(context,
RepositoryFactoryInformation.class).values();
for (RepositoryFactoryInformation entry : providers) {
EntityInformation<Object, Serializable> metadata =
entry.getEntityInformation();
Class<CrudRepository<Object, Serializable>> objectType =
entry.getRepositoryInterface();
CrudRepository<Object, Serializable> repository =
BeanFactoryUtils.beanOfType(context, objectType);
EntityInformation<Object, Serializable> metadata = entry.getEntityInformation();
Class<CrudRepository<Object, Serializable>> objectType = entry.getRepositoryInterface();
CrudRepository<Object, Serializable> repository = BeanFactoryUtils.beanOfType(context, objectType);
this.repositories.put(metadata, repository);
}

View File

@@ -26,31 +26,27 @@ import org.springframework.data.repository.core.EntityInformation;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Generic {@link PropertyEditor} to map entities handled by a
* {@link CrudRepository} to their id's and vice versa.
*
* Generic {@link PropertyEditor} to map entities handled by a {@link CrudRepository} to their id's and vice versa.
*
* @author Oliver Gierke
*/
public class DomainClassPropertyEditor<T, ID extends Serializable> extends
PropertyEditorSupport {
public class DomainClassPropertyEditor<T, ID extends Serializable> extends PropertyEditorSupport {
private final CrudRepository<T, ID> repository;
private final EntityInformation<T, ID> information;
private final PropertyEditorRegistry registry;
/**
* Creates a new {@link DomainClassPropertyEditor} for the given
* {@link CrudRepository}, {@link EntityInformation} and {@link PropertyEditorRegistry}.
*
* Creates a new {@link DomainClassPropertyEditor} for the given {@link CrudRepository}, {@link EntityInformation} and
* {@link PropertyEditorRegistry}.
*
* @param repository
* @param information
* @param registry
*/
public DomainClassPropertyEditor(CrudRepository<T, ID> repository, EntityInformation<T, ID> information,
PropertyEditorRegistry registry) {
PropertyEditorRegistry registry) {
Assert.notNull(repository);
Assert.notNull(registry);
@@ -60,7 +56,6 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends
this.registry = registry;
}
/*
* (non-Javadoc)
*
@@ -77,7 +72,6 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends
setValue(repository.findOne(getId(idAsString)));
}
/*
* (non-Javadoc)
*
@@ -97,12 +91,10 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends
return id == null ? null : id.toString();
}
/**
* Looks up the id of the given entity using one of the
* {@link org.synyx.hades.dao.orm.GenericDaoSupport.IdAware} implementations
* of Hades.
*
* Looks up the id of the given entity using one of the {@link org.synyx.hades.dao.orm.GenericDaoSupport.IdAware}
* implementations of Hades.
*
* @param entity
* @return
*/
@@ -111,13 +103,11 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends
return information.getId(entity);
}
/**
* Returns the actual typed id. Looks up an available customly registered
* {@link PropertyEditor} from the {@link PropertyEditorRegistry} before
* falling back on a {@link SimpleTypeConverter} to translate the
* {@link String} id into the type one.
*
* Returns the actual typed id. Looks up an available customly registered {@link PropertyEditor} from the
* {@link PropertyEditorRegistry} before falling back on a {@link SimpleTypeConverter} to translate the {@link String}
* id into the type one.
*
* @param idAsString
* @return
*/
@@ -133,11 +123,9 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends
return (ID) idEditor.getValue();
}
return new SimpleTypeConverter()
.convertIfNecessary(idAsString, idClass);
return new SimpleTypeConverter().convertIfNecessary(idAsString, idClass);
}
/*
* (non-Javadoc)
*
@@ -154,15 +142,12 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends
return false;
}
DomainClassPropertyEditor<?, ?> that =
(DomainClassPropertyEditor<?, ?>) obj;
DomainClassPropertyEditor<?, ?> that = (DomainClassPropertyEditor<?, ?>) obj;
return this.repository.equals(that.repository)
&& this.registry.equals(that.registry)
return this.repository.equals(that.repository) && this.registry.equals(that.registry)
&& this.information.equals(that.information);
}
/*
* (non-Javadoc)
*

View File

@@ -30,15 +30,11 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.support.RepositoryFactoryInformation;
/**
* Simple helper class to use Hades DAOs to provide
* {@link java.beans.PropertyEditor}s for domain classes. To get this working
* configure a
* {@link org.springframework.web.bind.support.ConfigurableWebBindingInitializer}
* for your
* {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
* and register the {@link DomainClassPropertyEditorRegistrar} there: <code>
* Simple helper class to use Hades DAOs to provide {@link java.beans.PropertyEditor}s for domain classes. To get this
* working configure a {@link org.springframework.web.bind.support.ConfigurableWebBindingInitializer} for your
* {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} and register the
* {@link DomainClassPropertyEditorRegistrar} there: <code>
* &lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt;
* &lt;property name="webBindingInitializer"&gt;
* &lt;bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"&gt;
@@ -48,19 +44,15 @@ import org.springframework.data.repository.core.support.RepositoryFactoryInforma
* &lt;/bean&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
* </code> Make sure this bean declaration is in the {@link ApplicationContext}
* created by the {@link DispatcherServlet} whereas the repositories need to be
* declared in the root
* </code> Make sure this bean declaration is in the {@link ApplicationContext} created by the {@link DispatcherServlet}
* whereas the repositories need to be declared in the root
* {@link org.springframework.web.context.WebApplicationContext}.
*
*
* @author Oliver Gierke
*/
public class DomainClassPropertyEditorRegistrar implements
PropertyEditorRegistrar, ApplicationContextAware {
private final Map<EntityInformation<Object, Serializable>, CrudRepository<Object, Serializable>> repositories =
new HashMap<EntityInformation<Object, Serializable>, CrudRepository<Object, Serializable>>();
public class DomainClassPropertyEditorRegistrar implements PropertyEditorRegistrar, ApplicationContextAware {
private final Map<EntityInformation<Object, Serializable>, CrudRepository<Object, Serializable>> repositories = new HashMap<EntityInformation<Object, Serializable>, CrudRepository<Object, Serializable>>();
/*
* (non-Javadoc)
@@ -77,15 +69,13 @@ public class DomainClassPropertyEditorRegistrar implements
EntityInformation<Object, Serializable> metadata = entry.getKey();
CrudRepository<Object, Serializable> repository = entry.getValue();
DomainClassPropertyEditor<Object, Serializable> editor =
new DomainClassPropertyEditor<Object, Serializable>(
repository, metadata, registry);
DomainClassPropertyEditor<Object, Serializable> editor = new DomainClassPropertyEditor<Object, Serializable>(
repository, metadata, registry);
registry.registerCustomEditor(metadata.getJavaType(), editor);
}
}
/*
* (non-Javadoc)
*
@@ -93,21 +83,17 @@ public class DomainClassPropertyEditorRegistrar implements
* org.springframework.context.ApplicationContextAware#setApplicationContext
* (org.springframework.context.ApplicationContext)
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({ "unchecked", "rawtypes" })
public void setApplicationContext(ApplicationContext context) {
Collection<RepositoryFactoryInformation> providers =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context,
RepositoryFactoryInformation.class).values();
Collection<RepositoryFactoryInformation> providers = BeanFactoryUtils.beansOfTypeIncludingAncestors(context,
RepositoryFactoryInformation.class).values();
for (RepositoryFactoryInformation information : providers) {
EntityInformation<Object, Serializable> metadata =
information.getEntityInformation();
Class<CrudRepository<Object, Serializable>> objectType =
information.getRepositoryInterface();
CrudRepository<Object, Serializable> repository =
BeanFactoryUtils.beanOfType(context, objectType);
EntityInformation<Object, Serializable> metadata = information.getEntityInformation();
Class<CrudRepository<Object, Serializable>> objectType = information.getRepositoryInterface();
CrudRepository<Object, Serializable> repository = BeanFactoryUtils.beanOfType(context, objectType);
this.repositories.put(metadata, repository);
}

View File

@@ -133,7 +133,7 @@ public abstract class ClassUtils {
return;
}
}
throw new IllegalStateException("Method has to have one of the following return types! " + Arrays.toString(types));
}

View File

@@ -17,7 +17,7 @@ package org.springframework.data.repository.util;
/**
* Simple constants holder.
*
*
* @author Oliver Gierke
*/
public abstract class TxUtils {
@@ -26,6 +26,5 @@ public abstract class TxUtils {
}
public static final String DEFAULT_TRANSACTION_MANAGER =
"transactionManager";
public static final String DEFAULT_TRANSACTION_MANAGER = "transactionManager";
}

View File

@@ -50,11 +50,13 @@ public class ChangeSetBackedTransactionSynchronization implements TransactionSyn
}
public void resume() {
throw new IllegalStateException("ChangedSetBackedTransactionSynchronization does not support transaction suspension currently.");
throw new IllegalStateException(
"ChangedSetBackedTransactionSynchronization does not support transaction suspension currently.");
}
public void suspend() {
throw new IllegalStateException("ChangedSetBackedTransactionSynchronization does not support transaction suspension currently.");
throw new IllegalStateException(
"ChangedSetBackedTransactionSynchronization does not support transaction suspension currently.");
}
}

View File

@@ -46,8 +46,7 @@ public class NaiveDoubleTransactionManager implements PlatformTransactionManager
return new DefaultTransactionStatus(t, ts.isNewTransaction(), false, false, false, null);
}
public TransactionStatus getTransaction(TransactionDefinition td)
throws TransactionException {
public TransactionStatus getTransaction(TransactionDefinition td) throws TransactionException {
TransactionStatus atx = a.getTransaction(td);
TransactionStatus btx = b.getTransaction(td);
status.put(atx, btx);

View File

@@ -26,7 +26,7 @@ import org.springframework.util.Assert;
/**
* Property information for a plain {@link Class}.
*
*
* @author Oliver Gierke
*/
public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
@@ -35,7 +35,7 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
/**
* Simple factory method to easily create new instances of {@link ClassTypeInformation}.
*
*
* @param <S>
* @param type
* @return
@@ -43,7 +43,7 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
public static <S> TypeInformation<S> from(Class<S> type) {
return new ClassTypeInformation<S>(type);
}
/**
* Creates a {@link TypeInformation} from the given method's return type.
*
@@ -57,15 +57,14 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
/**
* Creates {@link ClassTypeInformation} for the given type.
*
*
* @param type
*/
public ClassTypeInformation(Class<S> type) {
this(type, GenericTypeResolver.getTypeVariableMap(type));
}
@SuppressWarnings("rawtypes")
@SuppressWarnings("rawtypes")
ClassTypeInformation(Class<S> type, Map<TypeVariable, Type> typeVariableMap) {
super(type, typeVariableMap);
this.type = type;

View File

@@ -32,14 +32,14 @@ import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
/**
* Copy of Spring's {@link org.springframework.core.GenericTypeResolver}. Needed
* until {@link #getTypeVariableMap(Class)} gets public.
* Copy of Spring's {@link org.springframework.core.GenericTypeResolver}. Needed until
* {@link #getTypeVariableMap(Class)} gets public.
* <p/>
* TODO: remove that class, as soon as Spring 3.0.6 gets released.
*
*
* @see SPR-8005
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@SuppressWarnings({ "rawtypes", "unchecked" })
abstract class GenericTypeResolver {
/**
@@ -50,19 +50,17 @@ abstract class GenericTypeResolver {
/**
* Determine the target type for the given parameter specification.
*
*
* @param methodParam the method parameter specification
* @return the corresponding generic parameter type
*/
public static Type getTargetType(MethodParameter methodParam) {
Assert.notNull(methodParam, "MethodParameter must not be null");
if (methodParam.getConstructor() != null) {
return methodParam.getConstructor().getGenericParameterTypes()[methodParam
.getParameterIndex()];
return methodParam.getConstructor().getGenericParameterTypes()[methodParam.getParameterIndex()];
} else {
if (methodParam.getParameterIndex() >= 0) {
return methodParam.getMethod().getGenericParameterTypes()[methodParam
.getParameterIndex()];
return methodParam.getMethod().getGenericParameterTypes()[methodParam.getParameterIndex()];
} else {
return methodParam.getMethod().getGenericReturnType();
}
@@ -70,15 +68,12 @@ abstract class GenericTypeResolver {
}
/**
* Resolve the single type argument of the given generic interface against the
* given target class which is assumed to implement the generic interface and
* possibly declare a concrete type for its type variable.
*
* @param clazz the target class to check against
* @param genericIfc the generic interface or superclass to resolve the type argument
* from
* @return the resolved type of the argument, or <code>null</code> if not
* resolvable
* Resolve the single type argument of the given generic interface against the given target class which is assumed to
* implement the generic interface and possibly declare a concrete type for its type variable.
*
* @param clazz the target class to check against
* @param genericIfc the generic interface or superclass to resolve the type argument from
* @return the resolved type of the argument, or <code>null</code> if not resolvable
*/
public static Class<?> resolveTypeArgument(Class clazz, Class genericIfc) {
Class[] typeArgs = resolveTypeArguments(clazz, genericIfc);
@@ -86,31 +81,26 @@ abstract class GenericTypeResolver {
return null;
}
if (typeArgs.length != 1) {
throw new IllegalArgumentException(
"Expected 1 type argument on generic interface ["
+ genericIfc.getName() + "] but found " + typeArgs.length);
throw new IllegalArgumentException("Expected 1 type argument on generic interface [" + genericIfc.getName()
+ "] but found " + typeArgs.length);
}
return typeArgs[0];
}
/**
* Resolve the type arguments of the given generic interface against the given
* target class which is assumed to implement the generic interface and
* possibly declare concrete types for its type variables.
*
* @param clazz the target class to check against
* @param genericIfc the generic interface or superclass to resolve the type argument
* from
* @return the resolved type of each argument, with the array size matching
* the number of actual type arguments, or <code>null</code> if not
* resolvable
* Resolve the type arguments of the given generic interface against the given target class which is assumed to
* implement the generic interface and possibly declare concrete types for its type variables.
*
* @param clazz the target class to check against
* @param genericIfc the generic interface or superclass to resolve the type argument from
* @return the resolved type of each argument, with the array size matching the number of actual type arguments, or
* <code>null</code> if not resolvable
*/
public static Class[] resolveTypeArguments(Class clazz, Class genericIfc) {
return doResolveTypeArguments(clazz, clazz, genericIfc);
}
private static Class[] doResolveTypeArguments(Class ownerClass,
Class classToIntrospect, Class genericIfc) {
private static Class[] doResolveTypeArguments(Class ownerClass, Class classToIntrospect, Class genericIfc) {
while (classToIntrospect != null) {
if (genericIfc.isInterface()) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
@@ -121,8 +111,7 @@ abstract class GenericTypeResolver {
}
}
} else {
Class[] result = doResolveTypeArguments(ownerClass,
classToIntrospect.getGenericSuperclass(), genericIfc);
Class[] result = doResolveTypeArguments(ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
if (result != null) {
return result;
}
@@ -132,8 +121,7 @@ abstract class GenericTypeResolver {
return null;
}
private static Class[] doResolveTypeArguments(Class ownerClass, Type ifc,
Class genericIfc) {
private static Class[] doResolveTypeArguments(Class ownerClass, Type ifc, Class genericIfc) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
@@ -179,27 +167,24 @@ abstract class GenericTypeResolver {
/**
* Resolve the specified generic type against the given TypeVariable map.
*
* @param genericType the generic type to resolve
*
* @param genericType the generic type to resolve
* @param typeVariableMap the TypeVariable Map to resolved against
* @return the type if it resolves to a Class, or <code>Object.class</code>
* otherwise
* @return the type if it resolves to a Class, or <code>Object.class</code> otherwise
*/
static Class resolveType(Type genericType,
Map<TypeVariable, Type> typeVariableMap) {
static Class resolveType(Type genericType, Map<TypeVariable, Type> typeVariableMap) {
Type rawType = getRawType(genericType, typeVariableMap);
return (rawType instanceof Class ? (Class) rawType : Object.class);
}
/**
* Determine the raw type for the given generic parameter type.
*
* @param genericType the generic type to resolve
*
* @param genericType the generic type to resolve
* @param typeVariableMap the TypeVariable Map to resolved against
* @return the resolved raw type
*/
static Type getRawType(Type genericType,
Map<TypeVariable, Type> typeVariableMap) {
static Type getRawType(Type genericType, Map<TypeVariable, Type> typeVariableMap) {
Type resolvedType = genericType;
if (genericType instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) genericType;
@@ -216,9 +201,8 @@ abstract class GenericTypeResolver {
}
/**
* Build a mapping of {@link TypeVariable#getName TypeVariable names} to
* concrete {@link Class} for the specified {@link Class}. Searches all super
* types, enclosing types and interfaces.
* Build a mapping of {@link TypeVariable#getName TypeVariable names} to concrete {@link Class} for the specified
* {@link Class}. Searches all super types, enclosing types and interfaces.
*/
static Map<TypeVariable, Type> getTypeVariableMap(Class clazz) {
Reference<Map<TypeVariable, Type>> ref = typeVariableCache.get(clazz);
@@ -228,8 +212,7 @@ abstract class GenericTypeResolver {
typeVariableMap = new HashMap<TypeVariable, Type>();
// interfaces
extractTypeVariablesFromGenericInterfaces(clazz.getGenericInterfaces(),
typeVariableMap);
extractTypeVariablesFromGenericInterfaces(clazz.getGenericInterfaces(), typeVariableMap);
// super class
Type genericType = clazz.getGenericSuperclass();
@@ -239,8 +222,7 @@ abstract class GenericTypeResolver {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
}
extractTypeVariablesFromGenericInterfaces(type.getGenericInterfaces(),
typeVariableMap);
extractTypeVariablesFromGenericInterfaces(type.getGenericInterfaces(), typeVariableMap);
genericType = type.getGenericSuperclass();
type = type.getSuperclass();
}
@@ -256,8 +238,7 @@ abstract class GenericTypeResolver {
type = type.getEnclosingClass();
}
typeVariableCache.put(clazz, new WeakReference<Map<TypeVariable, Type>>(
typeVariableMap));
typeVariableCache.put(clazz, new WeakReference<Map<TypeVariable, Type>>(typeVariableMap));
}
return typeVariableMap;
@@ -278,31 +259,28 @@ abstract class GenericTypeResolver {
return bound;
}
private static void extractTypeVariablesFromGenericInterfaces(
Type[] genericInterfaces, Map<TypeVariable, Type> typeVariableMap) {
private static void extractTypeVariablesFromGenericInterfaces(Type[] genericInterfaces,
Map<TypeVariable, Type> typeVariableMap) {
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericInterface;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
if (pt.getRawType() instanceof Class) {
extractTypeVariablesFromGenericInterfaces(
((Class) pt.getRawType()).getGenericInterfaces(), typeVariableMap);
extractTypeVariablesFromGenericInterfaces(((Class) pt.getRawType()).getGenericInterfaces(), typeVariableMap);
}
} else if (genericInterface instanceof Class) {
extractTypeVariablesFromGenericInterfaces(
((Class) genericInterface).getGenericInterfaces(), typeVariableMap);
extractTypeVariablesFromGenericInterfaces(((Class) genericInterface).getGenericInterfaces(), typeVariableMap);
}
}
}
/**
* Read the {@link TypeVariable TypeVariables} from the supplied
* {@link ParameterizedType} and add mappings corresponding to the
* {@link TypeVariable#getName TypeVariable name} -> concrete type to the
* supplied {@link Map}.
* Read the {@link TypeVariable TypeVariables} from the supplied {@link ParameterizedType} and add mappings
* corresponding to the {@link TypeVariable#getName TypeVariable name} -> concrete type to the supplied {@link Map}.
* <p/>
* Consider this case:
* <p/>
*
* <pre class="code>
* public interface Foo<S, T> {
* ..
@@ -313,15 +291,14 @@ abstract class GenericTypeResolver {
* }
* </pre>
* <p/>
* For '<code>FooImpl</code>' the following mappings would be added to the
* {@link Map}: {S=java.lang.String, T=java.lang.Integer}.
* For '<code>FooImpl</code>' the following mappings would be added to the {@link Map}: {S=java.lang.String,
* T=java.lang.Integer}.
*/
private static void populateTypeMapFromParameterizedType(
ParameterizedType type, Map<TypeVariable, Type> typeVariableMap) {
private static void populateTypeMapFromParameterizedType(ParameterizedType type,
Map<TypeVariable, Type> typeVariableMap) {
if (type.getRawType() instanceof Class) {
Type[] actualTypeArguments = type.getActualTypeArguments();
TypeVariable[] typeVariables = ((Class) type.getRawType())
.getTypeParameters();
TypeVariable[] typeVariables = ((Class) type.getRawType()).getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
Type actualTypeArgument = actualTypeArguments[i];
TypeVariable variable = typeVariables[i];

View File

@@ -29,13 +29,12 @@ import org.springframework.util.ObjectUtils;
* @author Oliver Gierke
*/
class ParameterizedTypeInformation<T> extends TypeDiscoverer<T> {
private final TypeDiscoverer<?> parent;
/**
* Creates a new {@link ParameterizedTypeInformation} for the given {@link Type} and parent {@link TypeDiscoverer}.
*
*
* @param type must not be {@literal null}
* @param parent must not be {@literal null}
*/
@@ -44,10 +43,10 @@ class ParameterizedTypeInformation<T> extends TypeDiscoverer<T> {
Assert.notNull(parent);
this.parent = parent;
}
/**
* Considers the parent's type variable map before invoking the super class method.
*
*
* @return
*/
@SuppressWarnings("rawtypes")
@@ -55,7 +54,7 @@ class ParameterizedTypeInformation<T> extends TypeDiscoverer<T> {
return parent != null ? parent.getTypeVariableMap() : super.getTypeVariableMap();
}
/* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#createInfo(java.lang.reflect.Type)
*/
@@ -64,10 +63,10 @@ class ParameterizedTypeInformation<T> extends TypeDiscoverer<T> {
if (parent.getType().equals(fieldType)) {
return parent;
}
return super.createInfo(fieldType);
}
/*
* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#equals(java.lang.Object)
@@ -78,15 +77,15 @@ class ParameterizedTypeInformation<T> extends TypeDiscoverer<T> {
if (!super.equals(obj)) {
return false;
}
if (!this.getClass().equals(obj.getClass())) {
return false;
}
ParameterizedTypeInformation<?> that = (ParameterizedTypeInformation<?>) obj;
return this.parent == null ? that.parent == null : this.parent.equals(that.parent);
}
/*
* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#hashCode()

Some files were not shown because too many files have changed in this diff Show More