Formatting.
This commit is contained in:
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.data.mapping;
|
||||
|
||||
|
||||
/**
|
||||
* Value object to capture {@link Association}s.
|
||||
*
|
||||
|
||||
@@ -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}.
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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>> {
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple impementation of {@link PersistentProperty}.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package org.springframework.data.persistence;
|
||||
|
||||
|
||||
/**
|
||||
* Interface introduced to objects exposing ChangeSet information
|
||||
*
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* Simple ChangeSet implementation backed by a HashMap.
|
||||
*
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.querydsl;
|
||||
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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}.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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>
|
||||
* <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
|
||||
* <property name="webBindingInitializer">
|
||||
* <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
|
||||
@@ -48,19 +44,15 @@ import org.springframework.data.repository.core.support.RepositoryFactoryInforma
|
||||
* </bean>
|
||||
* </property>
|
||||
* </bean>
|
||||
* </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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user