From b0a04b16c6b231312562d6a6589a32a892594e47 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 1 Mar 2011 20:37:18 +0100 Subject: [PATCH 1/8] Added getBindableValue(int index) to ParameterAccessor. Adapted ParametersParameterAccessor accordingly. --- .../data/repository/query/ParameterAccessor.java | 13 +++++++++++++ .../query/ParametersParameterAccessor.java | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java index cd08e87e5..a15c175b6 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParameterAccessor.java @@ -49,6 +49,19 @@ public interface ParameterAccessor extends Iterable { 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. + * + * @param index + * @return + */ + Object getBindableValue(int index); + + /** * Returns an iterator over all bindable parameters. This means * parameters implementing {@link Pageable} or {@link Sort} will not be diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java index 51bf82b8a..47c38be4f 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/ParametersParameterAccessor.java @@ -89,7 +89,14 @@ public class ParametersParameterAccessor implements ParameterAccessor { } - private Object getBindableValue(int index) { + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.query.ParameterAccessor#getBindableValue + * (int) + */ + public Object getBindableValue(int index) { return values[parameters.getBindableParameter(index).getIndex()]; } From 1b98d32a4fa12f1eeca70ec93427f141c7d78e82 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 1 Mar 2011 20:38:15 +0100 Subject: [PATCH 2/8] Extended resolveQuery of QueryLookupStrategy to take domain class as well. --- .../data/repository/query/QueryLookupStrategy.java | 3 ++- .../data/repository/support/RepositoryFactorySupport.java | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java index e88043d1c..5633e227c 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/QueryLookupStrategy.java @@ -54,7 +54,8 @@ public interface QueryLookupStrategy { * that can be executed afterwards. * * @param method + * @param domainClass * @return */ - RepositoryQuery resolveQuery(Method method); + RepositoryQuery resolveQuery(Method method, Class domainClass); } \ No newline at end of file diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/RepositoryFactorySupport.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/RepositoryFactorySupport.java index 567092d3f..5fa125449 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/RepositoryFactorySupport.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/RepositoryFactorySupport.java @@ -216,7 +216,10 @@ public abstract class RepositoryFactorySupport { getQueryLookupStrategy(queryLookupStrategyKey); for (Method method : metadata.getQueryMethods()) { - queries.put(method, lookupStrategy.resolveQuery(method)); + queries.put( + method, + lookupStrategy.resolveQuery(method, + repositoryInterface.getDomainClass())); } } From ff844d7cbcd11573dedbb7836b75adc159a53b48 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 1 Mar 2011 20:39:52 +0100 Subject: [PATCH 3/8] Changed getReturnedDomainClass to only resolve generic type for Collections and Pages. --- .../data/repository/util/ClassUtils.java | 14 +++++++++----- .../repository/util/ClassUtilsUnitTests.java | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/util/ClassUtils.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/util/ClassUtils.java index 2fdabe3e9..ef41bee9c 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/util/ClassUtils.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/util/ClassUtils.java @@ -22,6 +22,7 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collection; +import org.springframework.data.domain.Page; import org.springframework.data.repository.Repository; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; @@ -52,15 +53,18 @@ public abstract class ClassUtils { */ public static Class getReturnedDomainClass(Method method) { - Type type = method.getGenericReturnType(); + Class returnType = method.getReturnType(); + + if (Collection.class.isAssignableFrom(returnType) + || Page.class.isAssignableFrom(returnType)) { + + Type type = method.getGenericReturnType(); - if (type instanceof ParameterizedType) { return (Class) ((ParameterizedType) type) .getActualTypeArguments()[0]; - - } else { - return method.getReturnType(); } + + return returnType; } diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java index e8a111f35..98df4b23b 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java @@ -41,6 +41,17 @@ public class ClassUtilsUnitTests { } + @Test + public void determinesReturnType() throws Exception { + + assertEquals(User.class, + getReturnedDomainClass(SomeDao.class.getMethod( + "findByFirstname", Pageable.class, String.class))); + assertEquals(GenericType.class, + getReturnedDomainClass(SomeDao.class.getMethod("someMethod"))); + } + + @Test public void determinesValidFieldsCorrectly() { @@ -79,5 +90,12 @@ public class ClassUtilsUnitTests { private interface SomeDao extends Serializable, UserRepository { Page findByFirstname(Pageable pageable, String firstname); + + + GenericType someMethod(); + } + + private class GenericType { + } } From 695f4ca9c00464599b57b99627759bfa9bc062b8 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 1 Mar 2011 20:42:14 +0100 Subject: [PATCH 4/8] Fixed sorting not being applied if provided via method parameter. AbstractQueryCreator now uses the Sort object from the parameters if the PartTree not already contains a Sort object (which got there due to a OrderBy directive in the method name). --- .../data/repository/query/parser/AbstractQueryCreator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java index 3ccdf52b1..182811375 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/AbstractQueryCreator.java @@ -62,7 +62,10 @@ public abstract class AbstractQueryCreator { */ public T createQuery() { - return complete(createCriteria(tree), tree.getSort()); + Sort treeSort = tree.getSort(); + Sort sort = treeSort != null ? treeSort : parameters.getSort(); + + return complete(createCriteria(tree), sort); } From cae2961275e01213114c5f126654e6ca1f8a32b2 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 2 Mar 2011 09:02:18 +0100 Subject: [PATCH 5/8] DATACMNS-19 - Fixed PersistableEntityMetadata. Added generics to PersistableEntityMetadata and let it being handed the actual domain class to return. --- .../support/PersistableEntityMetadata.java | 12 +-- .../PersistableEntityInformationTests.java | 83 ------------------- .../PersistableEntityMetadataUnitTests.java | 32 ++++++- src/main/resources/changelog.txt | 1 + 4 files changed, 36 insertions(+), 92 deletions(-) delete mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityInformationTests.java diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/PersistableEntityMetadata.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/PersistableEntityMetadata.java index 63ba9b016..bd2c16313 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/PersistableEntityMetadata.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/support/PersistableEntityMetadata.java @@ -26,17 +26,17 @@ import org.springframework.data.domain.Persistable; * @author Oliver Gierke */ @SuppressWarnings("rawtypes") -public class PersistableEntityMetadata extends - AbstractEntityMetadata { +public class PersistableEntityMetadata extends + AbstractEntityMetadata { /** * Creates a new {@link PersistableEntityMetadata}. * * @param domainClass */ - public PersistableEntityMetadata() { + public PersistableEntityMetadata(Class domainClass) { - super(Persistable.class); + super(domainClass); } @@ -48,7 +48,7 @@ public class PersistableEntityMetadata extends * .Object) */ @Override - public boolean isNew(Persistable entity) { + public boolean isNew(T entity) { return entity.isNew(); } @@ -61,7 +61,7 @@ public class PersistableEntityMetadata extends * org.springframework.data.repository.support.IdAware#getId(java.lang.Object * ) */ - public Object getId(Persistable entity) { + public Object getId(T entity) { return entity.getId(); } diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityInformationTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityInformationTests.java deleted file mode 100644 index 502a093e5..000000000 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityInformationTests.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2008-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.repository.support; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - -import org.junit.Test; -import org.springframework.data.domain.Persistable; - - -/** - * Unit test for {@link PersistableEntityMetadata}. - * - * @author Oliver Gierke - */ -public class PersistableEntityInformationTests { - - @Test - public void detectsPersistableCorrectly() throws Exception { - - PersistableEntityMetadata info = new PersistableEntityMetadata(); - - assertNewAndNoId(info, new PersistableEntity(null)); - assertNotNewAndId(info, new PersistableEntity(1L), 1L); - } - - - @SuppressWarnings("rawtypes") - private > void assertNewAndNoId( - S info, Persistable entity) { - - assertThat(info.isNew(entity), is(true)); - assertThat(info.getId(entity), is(nullValue())); - } - - - @SuppressWarnings("rawtypes") - private > void assertNotNewAndId( - S info, Persistable entity, Object id) { - - assertThat(info.isNew(entity), is(false)); - assertThat(info.getId(entity), is(id)); - } - - static class PersistableEntity implements Persistable { - - private static final long serialVersionUID = -5898780128204716452L; - - private final Long id; - - - public PersistableEntity(Long id) { - - this.id = id; - } - - - public Long getId() { - - return id; - } - - - public boolean isNew() { - - return id == null; - } - } -} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityMetadataUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityMetadataUnitTests.java index b22620b91..a376376d9 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityMetadataUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/support/PersistableEntityMetadataUnitTests.java @@ -34,15 +34,15 @@ import org.springframework.data.domain.Persistable; @RunWith(MockitoJUnitRunner.class) public class PersistableEntityMetadataUnitTests { - static final PersistableEntityMetadata metadata = - new PersistableEntityMetadata(); + @SuppressWarnings("rawtypes") + static final PersistableEntityMetadata metadata = + new PersistableEntityMetadata(Persistable.class); @Mock Persistable persistable; @Test - @SuppressWarnings("serial") public void usesPersistablesGetId() throws Exception { when(persistable.getId()).thenReturn(2L, 1L, 3L); @@ -59,4 +59,30 @@ public class PersistableEntityMetadataUnitTests { assertThat(metadata.isNew(persistable), is(true)); assertThat(metadata.isNew(persistable), is(false)); } + + + @Test + public void returnsGivenClassAsEntityType() throws Exception { + + PersistableEntityMetadata info = + new PersistableEntityMetadata( + PersistableEntity.class); + + assertEquals(PersistableEntity.class, info.getJavaType()); + } + + @SuppressWarnings("serial") + static class PersistableEntity implements Persistable { + + public Long getId() { + + return null; + } + + + public boolean isNew() { + + return false; + } + } } diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index 6378d132e..be90e9b5b 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -9,6 +9,7 @@ Repository * Added support for 'Distinct' keyword in finder method names (DATACMNS-15) * Added support for 'In' and 'NotIn' keywords (DATACMNS-16) * Introduced metamodel for entities and repositories (DATACMNS-17) +* Fixed returning wrong class PersistableEntityMetadata(DATACMNS-19) Changes in version 1.0.0.M3 (2011-02-09) ---------------------------------------- From 3a6113c5e832c5501a1b0d9e61ab2d3d437f5fd7 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 2 Mar 2011 11:14:50 +0100 Subject: [PATCH 6/8] Added toString methods to make debugging easier. --- .../data/repository/query/parser/Part.java | 12 +++++++++ .../repository/query/parser/PartTree.java | 27 +++++++++++++++++++ .../query/parser/PartTreeUnitTests.java | 11 ++++++++ 3 files changed, 50 insertions(+) diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java index d16eed9cc..85eb537d8 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Part.java @@ -113,6 +113,18 @@ public class Part { } + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + + return String.format("%s %s", property.getName(), type); + } + + /** * @return the type */ diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java index 0bf145a22..826799ac5 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java @@ -27,6 +27,7 @@ import java.util.regex.Pattern; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.parser.PartTree.OrPart; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** @@ -179,6 +180,20 @@ public class PartTree implements Iterable { return group != null && group.contains(DISTINCT); } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + + return String.format("%s %s", + StringUtils.collectionToDelimitedString(nodes, " or "), + orderBySource.toString()); + } + /** * A part of the parsed source that results from splitting up the resource * ar {@literal Or} keywords. Consists of {@link Part}s that have to be @@ -209,6 +224,18 @@ public class PartTree implements Iterable { } + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + + return StringUtils.collectionToDelimitedString(children, " and "); + } + + /* * (non-Javadoc) * diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java index f7223d120..1f1f9c2f2 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java @@ -82,6 +82,17 @@ public class PartTreeUnitTests { } + @Test + public void parsesCombinedAndAndOrPropertiesCorrectly() throws Exception { + + PartTree tree = + new PartTree("firstnameAndLastnameOrLastname", User.class); + assertPart(tree, new Part[] { new Part("firstname", User.class), + new Part("lastname", User.class) }, new Part[] { new Part( + "lastname", User.class) }); + } + + @Test public void hasSortIfOrderByIsGiven() throws Exception { From 841c78acb69a2403d47d5429310225275472cafe Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Wed, 2 Mar 2011 08:57:20 -0500 Subject: [PATCH 7/8] DATADOC-48 moving over cross-store code from previous prototype --- spring-data-commons-aspects/.classpath | 4 +- .../.settings/org.eclipse.jdt.core.prefs | 15 +- spring-data-commons-aspects/pom.xml | 12 ++ .../AsynchStoreCompletionListener.java | 32 +++++ .../persistence/EntityOperations.java | 78 +++++++++++ .../persistence/OrderedEntityOperations.java | 38 ++++++ .../persistence/RelatedEntity.java | 65 +++++++++ .../AbstractDeferredUpdateMixinFields.aj | 129 ++++++++++++++++++ .../persistence/support/ChangeSet.java | 24 ++++ .../persistence/support/ChangeSetBacked.java | 13 ++ .../support/ChangeSetConfiguration.java | 28 ++++ .../support/ChangeSetPersister.java | 47 +++++++ .../support/ChangeSetSynchronizer.java | 28 ++++ ...edSetBackedTransactionSynchronization.java | 66 +++++++++ .../persistence/support/HashMapChangeSet.java | 51 +++++++ ...SimpleReflectiveChangeSetSynchronizer.java | 96 +++++++++++++ spring-data-commons-aspects/template.mf | 4 +- 17 files changed, 723 insertions(+), 7 deletions(-) create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/AsynchStoreCompletionListener.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/EntityOperations.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/OrderedEntityOperations.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/RelatedEntity.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/AbstractDeferredUpdateMixinFields.aj create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSet.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetBacked.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetConfiguration.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetPersister.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetSynchronizer.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangedSetBackedTransactionSynchronization.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/HashMapChangeSet.java create mode 100644 spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/SimpleReflectiveChangeSetSynchronizer.java diff --git a/spring-data-commons-aspects/.classpath b/spring-data-commons-aspects/.classpath index 16f01e2ee..19ed14911 100644 --- a/spring-data-commons-aspects/.classpath +++ b/spring-data-commons-aspects/.classpath @@ -1,7 +1,7 @@ - - + + diff --git a/spring-data-commons-aspects/.settings/org.eclipse.jdt.core.prefs b/spring-data-commons-aspects/.settings/org.eclipse.jdt.core.prefs index e78b07017..c4dacddd4 100644 --- a/spring-data-commons-aspects/.settings/org.eclipse.jdt.core.prefs +++ b/spring-data-commons-aspects/.settings/org.eclipse.jdt.core.prefs @@ -1,6 +1,13 @@ -#Wed Nov 17 12:20:43 EST 2010 +#Tue Mar 01 12:59:14 EST 2011 eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/spring-data-commons-aspects/pom.xml b/spring-data-commons-aspects/pom.xml index 7d0c99b3a..9bbc0d239 100644 --- a/spring-data-commons-aspects/pom.xml +++ b/spring-data-commons-aspects/pom.xml @@ -81,6 +81,13 @@ true + + + org.hibernate.javax.persistence + hibernate-jpa-2.0-api + 1.0.0.Final + + org.mockito mockito-all @@ -108,6 +115,11 @@ Springframework Maven SNAPSHOT Repository http://maven.springframework.org/snapshot + + jboss-repository + JBoss Public Repository + http://repository.jboss.org/nexus/content/groups/public-jboss + diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/AsynchStoreCompletionListener.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/AsynchStoreCompletionListener.java new file mode 100644 index 000000000..4f417bb57 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/AsynchStoreCompletionListener.java @@ -0,0 +1,32 @@ +package org.springframework.persistence; + +import java.lang.reflect.Field; + +/** + * Listener interface for asynchronous storage operations. + * Can be annotated with OnlyOnFailure as an optimization + * if the listener is only interested in compensating transactions + * in the event of write failure. + * + * @author Rod Johnson + * + * @param new value type + */ +public interface AsynchStoreCompletionListener { + + /** + * Constant indicating no store completion action + */ + class NONE implements AsynchStoreCompletionListener { + public void onCompletion(AsynchStoreCompletionListener.StoreResult result, Object newValue, Field foreignStore) {} + } + + enum StoreResult { + SUCCESS, + FAILURE, + INDETERMINATE + }; + + void onCompletion(StoreResult result, V newValue, Field foreignStore); + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/EntityOperations.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/EntityOperations.java new file mode 100644 index 000000000..df6aa2f49 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/EntityOperations.java @@ -0,0 +1,78 @@ +package org.springframework.persistence; + +import java.lang.reflect.Field; + +import org.springframework.dao.DataAccessException; + +/** + * Interface to be implemented for each persistence technology, + * handling operations for the relevant entity type. + * Parameters: Key=K, Entity class=E + * + * @author Rod Johnson + */ +public interface EntityOperations { + + /** + * Is this clazz supported by the current EntityOperations? + * @param entityClass + * @param fs ForeignStore annotation, may be null + * @return + */ + boolean supports(Class entityClass, RelatedEntity fs); + + /** + * Return null if not found + * @param + * @param entityClass + * @param pk + * @return + * @throws DataAccessException + */ + E findEntity(Class entityClass, K pk) throws DataAccessException; + + /** + * Find the unique key for the given entity whose class this EntityOperations + * understands. For example, it might be the id property value. + * @param entity + * @return + * @throws DataAccessException + */ + K findUniqueKey(E entity) throws DataAccessException; + + /** + * + * @param entityClass + * @return the type of the unique key for this supported entity + * @throws DataAccessException + */ + Class uniqueKeyType(Class entityClass) throws DataAccessException; + + boolean isTransient(E entity) throws DataAccessException; + + /** + * Persist. Will cause key to be non-null. + * @param owner Persistent root entity, which has the RelatedEntity field + * @param entity + * @param f Foreign store field for entity being persisted + * @param fs ForeignStore annotation + * @throws DataAccessException + * @return the new unique key + */ + K makePersistent(Object owner, E entity, Field f, RelatedEntity fs) throws DataAccessException; + + /** + * Is this type of entity transactional? + * @return + */ + boolean isTransactional(); + + /** + * Should the field be cached in the entity? For some entity types + * such as streams, there should be no caching, and the value + * should be retrieved from the persistent store every time. + * @return + */ + boolean cacheInEntity(); + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/OrderedEntityOperations.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/OrderedEntityOperations.java new file mode 100644 index 000000000..e1cf11a83 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/OrderedEntityOperations.java @@ -0,0 +1,38 @@ +package org.springframework.persistence; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.Ordered; +import org.springframework.dao.DataAccessException; + +/** + * Convenient base class for EntityOperations implementations + * that adds ordering support. + * @author Rod Johnson + * + * @param + * @param + */ +public abstract class OrderedEntityOperations implements EntityOperations, Ordered { + + protected final Log log = LogFactory.getLog(getClass()); + + private int order = Integer.MAX_VALUE; + + @Override + public int getOrder() { + return this.order; + } + + public void setOrder(int order) { + this.order = order; + } + + /** + * Convenient default. Subclasses with non-Long key types can override this if they wish. + */ + @Override + public Class uniqueKeyType(Class entityClass) throws DataAccessException { + return Long.class; + } +} \ No newline at end of file diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/RelatedEntity.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/RelatedEntity.java new file mode 100644 index 000000000..f9e538c82 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/RelatedEntity.java @@ -0,0 +1,65 @@ +package org.springframework.persistence; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation indicating that a field may be stored in a foreign store + * and specifying the necessary guarantees. Conceptual rather than + * implementation-specific. + * @see ForeignStoreKeyManager + * + * @author Rod Johnson + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface RelatedEntity { + + /** + * + * Optional information as to how to compute or locate the key value. + * Some strategies may take this into account. + */ + String keyExpression() default ""; + + /** + * Should we use the key of the present entity + * @return + */ + boolean sameKey() default false; + + /** + * Policies for persistence + * @return + */ + PersistencePolicy policy() default @PersistencePolicy(); + + /** + * Name for the preferred data store. Merely a hint. May not be followed. + * @return + */ + String preferredStore() default ""; + + /** + * Is asynchronous store OK? + * @return + */ + boolean asynchStore() default false; + + // TODO - indicates if an asynchronous write should begin + // only after commit of a transaction + boolean afterCommit() default false; + + /** + * Completion listener class. Only used if asynchStore is true. + * Must have a no-arg constructor. + * @return + */ + @SuppressWarnings("unchecked") + Class storeCompletionListenerClass() default AsynchStoreCompletionListener.NONE.class; + + String storeCompletionListenerBeanName() default ""; + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/AbstractDeferredUpdateMixinFields.aj b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/AbstractDeferredUpdateMixinFields.aj new file mode 100644 index 000000000..bdfe6ce5b --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/AbstractDeferredUpdateMixinFields.aj @@ -0,0 +1,129 @@ +package org.springframework.persistence.support; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import org.aspectj.lang.reflect.FieldSignature; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * Aspect that saves field access in a ChangeSet + * + * @author Rod Johnson + * @author Thomas Risberg + */ +public abstract aspect AbstractDeferredUpdateMixinFields extends AbstractTypeAnnotatingMixinFields { + + //------------------------------------------------------------------------- + // Configure aspect for whole system. + // init() method can be invoked automatically if the aspect is a Spring + // bean, or called in user code. + //------------------------------------------------------------------------- + // Aspect shared config + + private ChangeSetPersister changeSetPersister; + + private ChangeSetSynchronizer changeSetManager; + + public void setChangeSetConfiguration(ChangeSetConfiguration changeSetConfiguration) { + this.changeSetPersister = changeSetConfiguration.getChangeSetPersister(); + this.changeSetManager = changeSetConfiguration.getChangeSetManager(); + } + + //------------------------------------------------------------------------- + // Advise user-defined constructors of ChangeSetBacked objects to create a new + // backing ChangeSet + //------------------------------------------------------------------------- + pointcut arbitraryUserConstructorOfChangeSetBackedObject(ChangeSetBacked entity) : + execution((@ET ChangeSetBacked+).new(..)) && + !execution((@ET ChangeSetBacked+).new(ChangeSet)) && + this(entity); + + // Or could use cflow + pointcut finderConstructorOfChangeSetBackedObject(ChangeSetBacked entity, ChangeSet cs) : + execution((@ET ChangeSetBacked+).new(ChangeSet)) && + this(entity) && + args(cs); + + + before(ChangeSetBacked entity) : arbitraryUserConstructorOfChangeSetBackedObject(entity) { + entity.itdChangeSetPersister = changeSetPersister; + log.info("User-defined constructor called on ChangeSetBacked object of class " + entity.getClass()); + // Populate all properties + ChangeSet changeSet = new HashMapChangeSet(); + changeSetManager.populateChangeSet(changeSet, entity); + entity.setChangeSet(changeSet); + if (!TransactionSynchronizationManager.isSynchronizationActive()) { + throw new InvalidDataAccessResourceUsageException("No transaction synchronization is active"); + } + TransactionSynchronizationManager.registerSynchronization(new ChangedSetBackedTransactionSynchronization(changeSetPersister, entity)); + } + + before(ChangeSetBacked entity, ChangeSet changeSet) : finderConstructorOfChangeSetBackedObject(entity, changeSet) { + entity.itdChangeSetPersister = changeSetPersister; + changeSetManager.populateEntity(changeSet, entity); + + // Now leave an empty ChangeSet to listen only to future changes + entity.setChangeSet(new HashMapChangeSet()); + + if (!TransactionSynchronizationManager.isSynchronizationActive()) { + throw new InvalidDataAccessResourceUsageException("No transaction synchronization is active"); + } + TransactionSynchronizationManager.registerSynchronization(new ChangedSetBackedTransactionSynchronization(changeSetPersister, entity)); + } + + + //------------------------------------------------------------------------- + // ChangeSet-related mixins + //------------------------------------------------------------------------- + // Introduced field + private ChangeSet ChangeSetBacked.changeSet; + + private ChangeSetPersister ChangeSetBacked.itdChangeSetPersister; + + public void ChangeSetBacked.setChangeSet(ChangeSet cs) { + this.changeSet = cs; + } + + public ChangeSet ChangeSetBacked.getChangeSet() { + return changeSet; + } + + // Flush the entity state to the persistent store + public void ChangeSetBacked.flush() { + itdChangeSetPersister.persistState(this.getClass(), this.changeSet); + } + + public Object ChangeSetBacked.getId() { + return itdChangeSetPersister.getPersistentId(this.getClass(), this.changeSet); + } + + + //------------------------------------------------------------------------- + // Around advice for field get/set + //------------------------------------------------------------------------- + // Nothing to do on field get unless laziness desired + + Object around(ChangeSetBacked entity, Object newVal) : entityFieldSet(entity, newVal) { + Field f = ((FieldSignature) thisJoinPoint.getSignature()).getField(); + + String propName = f.getName();//getRedisPropertyName(thisJoinPoint.getSignature()); + if (newVal instanceof Number) { + log.info("SET " + f + " -> ChangeSet number value property [" + propName + "] with value=[" + newVal + "]"); + entity.getChangeSet().set(propName, (Number) newVal); + } + else if (newVal instanceof String) { + log.info("SET " + f + " -> ChangeSet string value property [" + propName + "] with value=[" + newVal + "]"); + entity.getChangeSet().set(propName, (String) newVal); + } + else { + log.info("Don't know how to SET " + f + " with value=[" + newVal + "]"); + } + return proceed(entity, newVal); + } + +} \ No newline at end of file diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSet.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSet.java new file mode 100644 index 000000000..2fa0ff0d6 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSet.java @@ -0,0 +1,24 @@ +package org.springframework.persistence.support; + +import java.util.Map; + +import org.springframework.core.convert.ConversionService; + +/** + * Interface representing the set of changes in an entity. + * + * @author Rod Johnson + * @author Thomas Risberg + * + */ +public interface ChangeSet { + + T get(String key, Class requiredClass, ConversionService cs); + + void set(String key, Object o); + + Map getValues(); + + Object removeProperty(String k); + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetBacked.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetBacked.java new file mode 100644 index 000000000..cf1994e74 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetBacked.java @@ -0,0 +1,13 @@ +package org.springframework.persistence.support; + + +/** + * Interface introduced to objects exposing ChangeSet information + * @author Rod Johnson + * @author Thomas Risberg + */ +public interface ChangeSetBacked { + + ChangeSet getChangeSet(); + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetConfiguration.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetConfiguration.java new file mode 100644 index 000000000..3bdd97f1b --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetConfiguration.java @@ -0,0 +1,28 @@ +package org.springframework.persistence.support; + +public class ChangeSetConfiguration { + + private ChangeSetPersister changeSetPersister; + + private ChangeSetSynchronizer changeSetManager; + + public ChangeSetPersister getChangeSetPersister() { + return changeSetPersister; + } + + public void setChangeSetPersister(ChangeSetPersister changeSetPersister) { + this.changeSetPersister = changeSetPersister; + } + + public ChangeSetSynchronizer getChangeSetManager() { + return changeSetManager; + } + + public void setChangeSetManager( + ChangeSetSynchronizer changeSetManager) { + this.changeSetManager = changeSetManager; + } + + + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetPersister.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetPersister.java new file mode 100644 index 000000000..2f63414b2 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetPersister.java @@ -0,0 +1,47 @@ +package org.springframework.persistence.support; + +import org.springframework.dao.DataAccessException; + +/** + * Interface to be implemented by classes that can synchronize + * between data stores and ChangeSets. + * @author Rod Johnson + * + * @param entity key + */ +public interface ChangeSetPersister { + + String ID_KEY = "_id"; + + String CLASS_KEY = "_class"; + + /** + * TODO how to tell when not found? throw exception? + */ + void getPersistentState(Class entityClass, K key, ChangeSet changeSet) throws DataAccessException, NotFoundException; + + /** + * Return id + * @param cs + * @return + * @throws DataAccessException + */ + K getPersistentId(Class entityClass, ChangeSet cs) throws DataAccessException; + + /** + * Return key + * @param cs Key may be null if not persistent + * @return + * @throws DataAccessException + */ + K persistState(Class entityClass, ChangeSet cs) throws DataAccessException; + + /** + * Exception thrown in alternate control flow if getPersistentState + * finds no entity data. + */ + class NotFoundException extends Exception { + + } + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetSynchronizer.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetSynchronizer.java new file mode 100644 index 000000000..098365e1a --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangeSetSynchronizer.java @@ -0,0 +1,28 @@ +package org.springframework.persistence.support; + +import java.util.Map; + +import org.springframework.dao.DataAccessException; + +/** + * Interface to be implemented by classes that can synchronize + * between entities and ChangeSets. + * @author Rod Johnson + * + * @param + */ +public interface ChangeSetSynchronizer { + + Map> persistentFields(Class entityClassClass); + + /** + * Take all entity fields into a changeSet. + * @param entity + * @return + * @throws DataAccessException + */ + void populateChangeSet(ChangeSet changeSet, E entity) throws DataAccessException; + + void populateEntity(ChangeSet changeSet, E entity) throws DataAccessException; + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangedSetBackedTransactionSynchronization.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangedSetBackedTransactionSynchronization.java new file mode 100644 index 000000000..82cf1c3a6 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/ChangedSetBackedTransactionSynchronization.java @@ -0,0 +1,66 @@ +package org.springframework.persistence.support; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.transaction.support.TransactionSynchronization; + +public class ChangedSetBackedTransactionSynchronization implements TransactionSynchronization { + + protected final Log log = LogFactory.getLog(getClass()); + + private ChangeSetPersister changeSetPersister; + + private ChangeSetBacked entity; + + private int changeSetTxStatus = -1; + + public ChangedSetBackedTransactionSynchronization(ChangeSetPersister changeSetPersister, ChangeSetBacked entity) { + this.changeSetPersister = changeSetPersister; + this.entity = entity; + } + + @Override + public void afterCommit() { + log.debug("After Commit called for " + entity); + changeSetPersister.persistState(entity.getClass(), entity.getChangeSet()); + changeSetTxStatus = 0; + } + + @Override + public void afterCompletion(int status) { + log.debug("After Completion called with status = " + status); + if (changeSetTxStatus == 0) { + if (status == STATUS_COMMITTED) { + // this is good + log.debug("ChangedSetBackedTransactionSynchronization completed successfully for " + this.entity); + } + else { + // this could be bad - TODO: compensate + log.error("ChangedSetBackedTransactionSynchronization failed for " + this.entity); + } + } + } + + @Override + public void beforeCommit(boolean readOnly) { + } + + @Override + public void beforeCompletion() { + } + + @Override + public void flush() { + } + + @Override + public void resume() { + throw new IllegalStateException("ChangedSetBackedTransactionSynchronization does not support transaction suspension currently."); + } + + @Override + public void suspend() { + throw new IllegalStateException("ChangedSetBackedTransactionSynchronization does not support transaction suspension currently."); + } + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/HashMapChangeSet.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/HashMapChangeSet.java new file mode 100644 index 000000000..e9fe86104 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/HashMapChangeSet.java @@ -0,0 +1,51 @@ +package org.springframework.persistence.support; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.core.convert.ConversionService; + +/** + * Simple ChangeSet implementation backed by a HashMap. + * @author Thomas Risberg + * @author Rod Johnson + */ +public class HashMapChangeSet implements ChangeSet { + + private Map values; + + public HashMapChangeSet(Map values) { + this.values = values; + } + + public HashMapChangeSet() { + this(new HashMap()); + } + + @Override + public void set(String key, Object o) { + values.put(key, o); + } + + @Override + public String toString() { + return "HashMapChangeSet: values=[" + values + "]"; + } + + @Override + public Map getValues() { + return Collections.unmodifiableMap(values); + } + + @Override + public Object removeProperty(String k) { + return this.values.remove(k); + } + + @Override + public T get(String key, Class requiredClass, ConversionService conversionService) { + return conversionService.convert(values.get(key), requiredClass); + } + +} diff --git a/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/SimpleReflectiveChangeSetSynchronizer.java b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/SimpleReflectiveChangeSetSynchronizer.java new file mode 100644 index 000000000..43b6f6b51 --- /dev/null +++ b/spring-data-commons-aspects/src/main/java/org/springframework/persistence/support/SimpleReflectiveChangeSetSynchronizer.java @@ -0,0 +1,96 @@ +package org.springframework.persistence.support; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionService; +import org.springframework.dao.DataAccessException; +import org.springframework.persistence.RelatedEntity; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.ReflectionUtils.FieldCallback; +import org.springframework.util.ReflectionUtils.FieldFilter; + +/** + * Synchronizes fields to ChangeSets, regardless of visibility. + * + * @author Rod Johnson + */ +public class SimpleReflectiveChangeSetSynchronizer implements ChangeSetSynchronizer { + + /** + * Filter matching infrastructure fields, so they can be excluded + */ + private static FieldFilter PERSISTABLE_FIELDS = new FieldFilter() { + @Override + public boolean matches(Field f) { + return !( + f.isSynthetic() || + Modifier.isStatic(f.getModifiers()) || + Modifier.isTransient(f.getModifiers()) || + f.getName().startsWith("ajc$") || + f.isAnnotationPresent(RelatedEntity.class) + ); + } + }; + + private final Log log = LogFactory.getLog(getClass()); + + private final ConversionService conversionService; + + @Autowired + public SimpleReflectiveChangeSetSynchronizer(ConversionService conversionService) { + this.conversionService = conversionService; + } + + @Override + public Map> persistentFields(Class entityClass) { + final Map> fields = new HashMap>(); + ReflectionUtils.doWithFields(entityClass, new FieldCallback() { + @Override + public void doWith(Field f) throws IllegalArgumentException, IllegalAccessException { + fields.put(f.getName(), f.getType()); + } + }, PERSISTABLE_FIELDS); + return fields; + } + + @Override + public void populateChangeSet(final ChangeSet changeSet, final ChangeSetBacked entity) throws DataAccessException { + ReflectionUtils.doWithFields(entity.getClass(), new FieldCallback() { + @Override + public void doWith(Field f) throws IllegalArgumentException, IllegalAccessException { + f.setAccessible(true); + if (log.isDebugEnabled()) { + log.debug("POPULATE ChangeSet value from entity field: " + f); + } + changeSet.set(f.getName(), f.get(entity)); + } + }, PERSISTABLE_FIELDS); + String classShortName = ClassUtils.getShortName(entity.getClass()); + changeSet.set("_class", classShortName); + } + + @Override + public void populateEntity(final ChangeSet changeSet, final ChangeSetBacked entity) throws DataAccessException { + ReflectionUtils.doWithFields(entity.getClass(), new FieldCallback() { + @Override + public void doWith(Field f) throws IllegalArgumentException, IllegalAccessException { + if (changeSet.getValues().containsKey(f.getName())) { + f.setAccessible(true); + if (log.isDebugEnabled()) { + log.debug("POPULATE entity from ChangeSet for field: " + f); + } + Object val = changeSet.get(f.getName(), f.getType(), conversionService); + f.set(entity, val); + } + } + }, PERSISTABLE_FIELDS); + } + +} diff --git a/spring-data-commons-aspects/template.mf b/spring-data-commons-aspects/template.mf index 1acd51461..84c7abd31 100644 --- a/spring-data-commons-aspects/template.mf +++ b/spring-data-commons-aspects/template.mf @@ -4,13 +4,15 @@ Bundle-Vendor: SpringSource Bundle-ManifestVersion: 2 Import-Package: sun.reflect;version="0";resolution:=optional +Excluded-Imports: + org.springframework.persistence Import-Template: org.springframework.beans.*;version="[3.0.0, 4.0.0)", org.springframework.core.*;version="[3.0.0, 4.0.0)", org.springframework.dao.*;version="[3.0.0, 4.0.0)", + org.springframework.transaction..*;version="[3.0.0, 4.0.0)", org.springframework.util.*;version="[3.0.0, 4.0.0)", org.springframework.data.core.*;version="[1.0.0, 2.0.0)", - org.springframework.data.persistence.*;version="[1.0.0, 2.0.0)", org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional, org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", org.aspectj.*;version="[1.6.5, 2.0.0)", From af99e4e8257cc639b452143b1c217de4f3b38143 Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Wed, 2 Mar 2011 10:07:58 -0500 Subject: [PATCH 8/8] moved DocBook to pre-site --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b88452e65..d83db4c97 100644 --- a/pom.xml +++ b/pom.xml @@ -133,7 +133,7 @@ generate-html generate-pdf - package + pre-site