Author: hardy.ferentschik
Date: 2009-06-25 11:43:42 -0400 (Thu, 25 Jun 2009)
New Revision: 16952
Added:
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/SequenceResolutionTest.java
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/TestEntity.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/groups/GroupChainTest.java
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/Group.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChain.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChainGenerator.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaData.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaDataImpl.java
Log:
HV-170 - Refactor the group sequence expansion and take the default sequence expansion of
the validated entity into considertation
Added:
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/SequenceResolutionTest.java
===================================================================
---
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/SequenceResolutionTest.java
(rev 0)
+++
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/SequenceResolutionTest.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -0,0 +1,44 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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.hibernate.jsr303.tck.tests.constraints.groups.defaultgroupsequence;
+
+import javax.validation.GroupDefinitionException;
+import javax.validation.Validator;
+
+import org.jboss.testharness.AbstractTest;
+import org.jboss.testharness.impl.packaging.Artifact;
+import org.jboss.testharness.impl.packaging.ArtifactType;
+import org.jboss.testharness.impl.packaging.Classes;
+import org.testng.annotations.Test;
+
+import org.hibernate.jsr303.tck.util.TestUtil;
+
+/**
+ * @author Hardy Ferentschik
+ */
+@Artifact(artifactType = ArtifactType.JSR303)
+@Classes({ TestUtil.class, TestUtil.PathImpl.class, TestUtil.NodeImpl.class })
+public class SequenceResolutionTest extends AbstractTest {
+
+ @Test(expectedExceptions = GroupDefinitionException.class)
+ public void testInvalidDefinitionOfDefaultSequenceInEntity() {
+ Validator validator = TestUtil.getDefaultValidator();
+ TestEntity entity = new TestEntity();
+ validator.validate( entity, Complete.class );
+ }
+}
Added:
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/TestEntity.java
===================================================================
---
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/TestEntity.java
(rev 0)
+++
beanvalidation/trunk/validation-tck/src/main/java/org/hibernate/jsr303/tck/tests/constraints/groups/defaultgroupsequence/TestEntity.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -0,0 +1,38 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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.hibernate.jsr303.tck.tests.constraints.groups.defaultgroupsequence;
+
+import javax.validation.GroupSequence;
+import javax.validation.constraints.NotNull;
+import javax.validation.groups.Default;
+
+/**
+ * @author Hardy Ferentschik
+ */
+@GroupSequence({ TimeConsumingChecks.class, TestEntity.class })
+public class TestEntity {
+ @NotNull
+ public String foo;
+}
+
+interface TimeConsumingChecks {
+}
+
+@GroupSequence({ Default.class, TimeConsumingChecks.class })
+interface Complete {
+}
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java 2009-06-25
11:12:54 UTC (rev 16951)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -75,13 +75,29 @@
private final transient GroupChainGenerator groupChainGenerator;
private final ConstraintValidatorFactory constraintValidatorFactory;
+
+ /**
+ * {@link MessageInterpolator} as passed to the constructor of this instance.
+ */
private final MessageInterpolator messageInterpolator;
- //never use it directly, always use getCachingTraversableResolver() to retrieved the
single threaded caching wrapper.
+
+ /**
+ * {@link TraversableResolver} as passed to the constructor of this instance.
+ * Never use it directly, always use {@link #getCachingTraversableResolver()} to
retrieved the single threaded caching wrapper.
+ */
private final TraversableResolver traversableResolver;
+
+ /**
+ * Passed at creation time of this validator instance.
+ */
private final ConstraintHelper constraintHelper;
+
+ /**
+ * Used to get access to the bean meta data. Used to avoid to parsing the constraint
configuration for each call
+ * of a given entity.
+ */
private final BeanMetaDataCache beanMetaDataCache;
-
public ValidatorImpl(ConstraintValidatorFactory constraintValidatorFactory,
MessageInterpolator messageInterpolator, TraversableResolver traversableResolver,
ConstraintHelper constraintHelper, BeanMetaDataCache beanMetaDataCache) {
this.constraintValidatorFactory = constraintValidatorFactory;
this.messageInterpolator = messageInterpolator;
@@ -96,6 +112,7 @@
if ( object == null ) {
throw new IllegalArgumentException( "Validation of a null object" );
}
+
GroupChain groupChain = determineGroupExecutionOrder( groups );
GlobalExecutionContext<T> context =
GlobalExecutionContext.getContextForValidate(
@@ -185,9 +202,13 @@
}
path = PathImpl.createShallowCopy( path );
-
LocalExecutionContext<U, V> localExecutionContext =
LocalExecutionContext.getLocalExecutionContext( value );
+ BeanMetaData<U> beanMetaData = getBeanMetaData(
localExecutionContext.getCurrentBeanType() );
+ if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
+
groupChain.assertDefaulGroupSequenceIsExpandable(beanMetaData.getDefaultGroupSequence());
+ }
+
// process first single groups. For these we can skip some object traversal, by first
running all validations on the current bean
// before traversing the object.
Iterator<Group> groupIterator = groupChain.getGroupIterator();
@@ -231,9 +252,7 @@
* @param <T> The type of the root bean
*/
private <T, U, V> void validateConstraints(GlobalExecutionContext<T>
executionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path)
{
- //casting rely on the fact that root object is at the top of the stack
- @SuppressWarnings("unchecked")
- BeanMetaData<T> beanMetaData = getBeanMetaData( ( Class<T> )
localExecutionContext.getCurrentBeanType() );
+ BeanMetaData<U> beanMetaData = getBeanMetaData(
localExecutionContext.getCurrentBeanType() );
if ( localExecutionContext.getCurrentGroup().getName().equals( Default.class.getName()
) ) {
List<Class<?>> defaultGroupSequence =
beanMetaData.getDefaultGroupSequence();
if ( log.isTraceEnabled() && defaultGroupSequence.size() > 0 &&
defaultGroupSequence.get( 0 ) != Default.class ) {
@@ -258,9 +277,9 @@
}
}
- private <T, U, V> boolean
validateConstraintsForCurrentGroup(GlobalExecutionContext<T> globalExecutionContext,
LocalExecutionContext<U, V> localExecutionContext, BeanMetaData<T>
beanMetaData, PathImpl path) {
+ private <T, U, V> boolean
validateConstraintsForCurrentGroup(GlobalExecutionContext<T> globalExecutionContext,
LocalExecutionContext<U, V> localExecutionContext, BeanMetaData<U>
beanMetaData, PathImpl path) {
boolean validationSuccessful = true;
- for ( MetaConstraint<T, ?> metaConstraint : beanMetaData.geMetaConstraintList() )
{
+ for ( MetaConstraint<U, ?> metaConstraint : beanMetaData.geMetaConstraintList() )
{
PathImpl newPath = PathImpl.createShallowCopy( path );
if ( !"".equals( metaConstraint.getPropertyName() ) ) {
newPath.addNode( new NodeImpl( metaConstraint.getPropertyName() ) );
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/Group.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/Group.java 2009-06-25
11:12:54 UTC (rev 16951)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/Group.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -25,7 +25,14 @@
* @author Hardy Ferentschik
*/
public class Group {
+ /**
+ * The actual group.
+ */
private Class<?> group;
+
+ /**
+ * The sequence the group is part of ({@code null}, if this group is not part of a
sequence).
+ */
private Class<?> sequence;
public Group(Class<?> group) {
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChain.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChain.java 2009-06-25
11:12:54 UTC (rev 16951)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChain.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -18,43 +18,41 @@
package org.hibernate.validation.engine.groups;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import javax.validation.GroupDefinitionException;
+import javax.validation.groups.Default;
/**
- * An instance of <code>GroupExecutionChain</code> defines the order in to
validate groups during the validation process.
+ * An instance of {@code GroupChain} defines the group order during one full validation
call.
*
* @author Hardy Ferentschik
*/
public class GroupChain {
/**
- * The list of single groups.
+ * The list of single groups to be used this validation.
*/
private List<Group> groupList = new ArrayList<Group>();
/**
- * The list of sequences.
+ * The different sequences for this validation. The map contains the list of groups
mapped to their sequence
+ * name.
*/
- private List<List<Group>> sequenceList = new
ArrayList<List<Group>>();
+ private Map<Class<?>, List<Group>> sequenceMap = new
HashMap<Class<?>, List<Group>>();
public Iterator<Group> getGroupIterator() {
return groupList.iterator();
}
public Iterator<List<Group>> getSequenceIterator() {
- return sequenceList.iterator();
+ return sequenceMap.values().iterator();
}
public boolean containsSequence(Class<?> groupSequence) {
- boolean result = false;
- for ( List<Group> sequence : sequenceList ) {
- if ( sequence.get( 0 ).getSequence().getName().equals( groupSequence.getName() ) ) {
- result = true;
- break;
- }
- }
- return result;
+ return sequenceMap.containsKey( groupSequence );
}
void insertGroup(Group group) {
@@ -68,8 +66,62 @@
return;
}
- if ( !sequenceList.contains( groups ) ) {
- sequenceList.add( groups );
+ if ( !sequenceMap.containsValue( groups ) ) {
+ sequenceMap.put( groups.get( 0 ).getSequence(), groups );
}
}
+
+ @Override
+ public String toString() {
+ return "GroupChain{" +
+ "groupList=" + groupList +
+ ", sequenceMap=" + sequenceMap +
+ '}';
+ }
+
+ public void assertDefaulGroupSequenceIsExpandable(List<Class<?>>
defaultGroupSequence) {
+ for ( Map.Entry<Class<?>, List<Group>> entry : sequenceMap.entrySet()
) {
+ Class<?> sequence = entry.getKey();
+ List<Group> groupList = entry.getValue();
+ List<Group> defaultGroupList = buildTempGroupList( defaultGroupSequence,
sequence );
+ int defaultGroupIndex = containsDefaultGroupAtIndex( sequence, groupList );
+ if ( defaultGroupIndex != -1 ) {
+ ensureDefaultGroupSequenceIsExpandable( groupList, defaultGroupList,
defaultGroupIndex );
+ }
+ }
+ }
+
+ private void ensureDefaultGroupSequenceIsExpandable(List<Group> groupList,
List<Group> defaultGroupList, int defaultGroupIndex) {
+ for ( int i = 0; i < defaultGroupList.size(); i++ ) {
+ Group group = defaultGroupList.get( i );
+ if(group.getGroup().equals( Default.class )) {
+ continue; // we don't have to consider the default group since it is the one we
want to replace
+ }
+ int index = groupList.indexOf( group ); // check whether the sequence contains group
of the default group sequence
+ if ( index == -1 ) {
+ continue; // if the group is not in the sequence we can continue
+ }
+
+ if ( ( i == 0 && index == defaultGroupIndex - 1 ) || ( i ==
defaultGroupList.size() - 1 && index == defaultGroupIndex + 1 ) ) {
+ // if we are at the beginning or end of he defaultGroupSequence and the matches are
either directly before resp after we can continue as well,
+ // since we basically have two groups
+ continue;
+ }
+ throw new GroupDefinitionException( "Unable to expand default group list" +
defaultGroupList + " into sequence " + groupList );
+ }
+ }
+
+ private int containsDefaultGroupAtIndex(Class<?> sequence, List<Group>
groupList) {
+ Group defaultGroup = new Group( Default.class, sequence );
+ return groupList.indexOf( defaultGroup );
+ }
+
+ private List<Group> buildTempGroupList(List<Class<?>>
defaultGroupSequence, Class<?> sequence) {
+ List<Group> groupList = new ArrayList<Group>();
+ for ( Class<?> clazz : defaultGroupSequence ) {
+ Group g = new Group( clazz, sequence );
+ groupList.add( g );
+ }
+ return groupList;
+ }
}
\ No newline at end of file
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChainGenerator.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChainGenerator.java 2009-06-25
11:12:54 UTC (rev 16951)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/groups/GroupChainGenerator.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -90,7 +90,7 @@
List<Group> resolvedGroupSequence = new ArrayList<Group>();
GroupSequence sequenceAnnotation = group.getAnnotation( GroupSequence.class );
Class<?>[] sequenceArray = sequenceAnnotation.value();
- for ( Class clazz : sequenceArray ) {
+ for ( Class<?> clazz : sequenceArray ) {
if ( clazz.getAnnotation( GroupSequence.class ) == null ) {
resolvedGroupSequence.add( new Group( clazz, group ) );
}
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaData.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaData.java 2009-06-25
11:12:54 UTC (rev 16951)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaData.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -24,8 +24,6 @@
import javax.validation.metadata.BeanDescriptor;
import javax.validation.metadata.PropertyDescriptor;
-import org.hibernate.validation.metadata.MetaConstraint;
-
/**
* Interface defining the meta data about the constraints defined in a given bean.
*
@@ -39,7 +37,7 @@
Class<T> getBeanClass();
/**
- * @return an instance of <code>ElementDescriptor</code> describing the bean
this meta data applies for.
+ * @return an instance of {@code ElementDescriptor} describing the bean this meta data
applies for.
*/
BeanDescriptor getBeanDescriptor();
@@ -54,17 +52,22 @@
List<Class<?>> getDefaultGroupSequence();
/**
- * @return A list of <code>MetaConstraint</code> instances encapsulating the
information of all the constraints
+ * @return {@code true} if the entity redefines the default group sequence, {@code
false} otherwise.
+ */
+ boolean defaultGroupSequenceIsRedefined();
+
+ /**
+ * @return A list of {@code MetaConstraint} instances encapsulating the information of
all the constraints
* defined on the bean.
*/
List<MetaConstraint<T, ? extends Annotation>> geMetaConstraintList();
/**
- * Return <code>PropertyDescriptor</code> for the given property.
+ * Return {@code PropertyDescriptor} for the given property.
*
* @param property the property for which to retrieve the descriptor.
*
- * @return Returns the <code>PropertyDescriptor</code> for the given
property or <code>null</code> in case the
+ * @return Returns the {@code PropertyDescriptor} for the given property or {@code null}
in case the
* property does not have a descriptor.
*/
PropertyDescriptor getPropertyDescriptor(String property);
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaDataImpl.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaDataImpl.java 2009-06-25
11:12:54 UTC (rev 16951)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/metadata/BeanMetaDataImpl.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -137,6 +137,10 @@
return Collections.unmodifiableList( defaultGroupSequence );
}
+ public boolean defaultGroupSequenceIsRedefined() {
+ return defaultGroupSequence.size() > 1;
+ }
+
public void setDefaultGroupSequence(List<Class<?>> groupSequence) {
defaultGroupSequence = new ArrayList<Class<?>>();
boolean groupSequenceContainsDefault = false;
@@ -331,7 +335,7 @@
@SuppressWarnings("unchecked")
private <A extends Annotation> ConstraintDescriptorImpl
buildConstraintDescriptor(Class<?> clazz, A annotation) {
ConstraintDescriptorImpl constraintDescriptor;
- if ( clazz.isInterface() && !clazz.equals( beanClass)) {
+ if ( clazz.isInterface() && !clazz.equals( beanClass ) ) {
constraintDescriptor = new ConstraintDescriptorImpl( annotation, constraintHelper,
clazz );
}
else {
Added:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/groups/GroupChainTest.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/groups/GroupChainTest.java
(rev 0)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/groups/GroupChainTest.java 2009-06-25
15:43:42 UTC (rev 16952)
@@ -0,0 +1,162 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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.hibernate.validation.engine.groups;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.GroupDefinitionException;
+import javax.validation.groups.Default;
+
+import static org.testng.FileAssert.fail;
+import org.testng.annotations.Test;
+
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class GroupChainTest {
+ @Test
+ public void testAssertDefaulGroupSequenceIsExpandableWithDefaultAtEndOfSequence() {
+ // create a dummy sequence
+ Group a = new Group( GroupA.class, TestSequence.class );
+ Group b = new Group( GroupB.class, TestSequence.class );
+ Group c = new Group( GroupC.class, TestSequence.class );
+ Group defaultGroup = new Group(
+ Default.class, TestSequence.class
+ );
+ List<Group> sequence = new ArrayList<Group>();
+ sequence.add( a );
+ sequence.add( b );
+ sequence.add( c );
+ sequence.add( defaultGroup );
+
+ GroupChain chain = new GroupChain();
+ chain.insertSequence( sequence );
+
+ // create test default sequence
+ List<Class<?>> defaultSequence = new ArrayList<Class<?>>();
+ defaultSequence.add( Default.class );
+ defaultSequence.add( GroupA.class );
+ try {
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+ fail();
+ }
+ catch ( GroupDefinitionException e ) {
+ // success
+ }
+
+ defaultSequence.clear();
+ defaultSequence.add( GroupA.class );
+ defaultSequence.add( Default.class );
+ try {
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+ fail();
+ }
+ catch ( GroupDefinitionException e ) {
+ // success
+ }
+
+ defaultSequence.clear();
+ defaultSequence.add( Default.class );
+ defaultSequence.add( GroupC.class );
+ try {
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+ fail();
+ }
+ catch ( GroupDefinitionException e ) {
+ // success
+ }
+
+ defaultSequence.clear();
+ defaultSequence.add( GroupC.class );
+ defaultSequence.add( Default.class );
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+ }
+
+
+ @Test
+ public void testAssertDefaulGroupSequenceIsExpandableWithDefaultAtBeginningOfSequence()
{
+ // create a dummy sequence
+ Group a = new Group( GroupA.class, TestSequence.class );
+ Group b = new Group( GroupB.class, TestSequence.class );
+ Group c = new Group( GroupC.class, TestSequence.class );
+ Group defaultGroup = new Group(
+ Default.class, TestSequence.class
+ );
+ List<Group> sequence = new ArrayList<Group>();
+ sequence.add( defaultGroup );
+ sequence.add( a );
+ sequence.add( b );
+ sequence.add( c );
+
+ GroupChain chain = new GroupChain();
+ chain.insertSequence( sequence );
+
+ // create test default sequence
+ List<Class<?>> defaultSequence = new ArrayList<Class<?>>();
+ defaultSequence.add( Default.class );
+ defaultSequence.add( GroupA.class );
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+
+
+ defaultSequence.clear();
+ defaultSequence.add( GroupA.class );
+ defaultSequence.add( Default.class );
+ try {
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+ fail();
+ }
+ catch ( GroupDefinitionException e ) {
+ // success
+ }
+
+ defaultSequence.clear();
+ defaultSequence.add( Default.class );
+ defaultSequence.add( GroupC.class );
+ try {
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+ fail();
+ }
+ catch ( GroupDefinitionException e ) {
+ // success
+ }
+
+ defaultSequence.clear();
+ defaultSequence.add( GroupC.class );
+ defaultSequence.add( Default.class );
+ try {
+ chain.assertDefaulGroupSequenceIsExpandable( defaultSequence );
+ fail();
+ }
+ catch ( GroupDefinitionException e ) {
+ // success
+ }
+ }
+}
+
+interface TestSequence {
+}
+
+interface GroupA {
+}
+
+interface GroupB {
+}
+
+interface GroupC {
+}