Return-Path: Delivered-To: apmail-incubator-bval-commits-archive@minotaur.apache.org Received: (qmail 11060 invoked from network); 29 Sep 2010 15:36:11 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 29 Sep 2010 15:36:11 -0000 Received: (qmail 12920 invoked by uid 500); 29 Sep 2010 15:36:11 -0000 Delivered-To: apmail-incubator-bval-commits-archive@incubator.apache.org Received: (qmail 12889 invoked by uid 500); 29 Sep 2010 15:36:10 -0000 Mailing-List: contact bval-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: bval-dev@incubator.apache.org Delivered-To: mailing list bval-commits@incubator.apache.org Received: (qmail 12882 invoked by uid 99); 29 Sep 2010 15:36:10 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 29 Sep 2010 15:36:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 29 Sep 2010 15:36:07 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 3107923889BF; Wed, 29 Sep 2010 15:35:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1002681 - in /incubator/bval/sandbox/lang3-work: bval-jsr303/src/main/java/ bval-jsr303/src/main/java/org/apache/bval/jsr303/util/ bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/ bval-jsr303d/src/test/java/org/apache/bval/jsr303... Date: Wed, 29 Sep 2010 15:35:47 -0000 To: bval-commits@incubator.apache.org From: mbenson@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100929153547.3107923889BF@eris.apache.org> Author: mbenson Date: Wed Sep 29 15:35:46 2010 New Revision: 1002681 URL: http://svn.apache.org/viewvc?rev=1002681&view=rev Log: PathNavigation is more structured, handling index/key-less iterables marked as []: thus, no wildcard sequence is needed for dynamic prototype iterables; make DynamicMetaGraphManager implementation function correctly by extracting the metabean-merging code into a standalone implementation class, then delegating dynamicMetaBeanFinder work to this. Added: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java (with props) incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java (with props) Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/ (props changed) incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Wed Sep 29 15:35:46 2010 @@ -1 +1 @@ -/incubator/bval/trunk/bval-jsr303/src/main/java:992330-992353,992401,992406,992412,992510,992648,993404-993438,996236,996240,997154 +/incubator/bval/trunk/bval-jsr303/src/main/java:992330-992353,992401,992406,992412,992510,992648,993404-993438,996236,996240,997154,1002445 Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java Wed Sep 29 15:35:46 2010 @@ -159,5 +159,12 @@ public class NestedPathNavigator { this.type = type; } + /** + * {@inheritDoc} + */ + public void handleGenericInIterable() { + throw new UnsupportedOperationException("Cannot navigate a ValidationContext to []"); + } + } } Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java Wed Sep 29 15:35:46 2010 @@ -49,6 +49,11 @@ public class PathNavigation { void handleIndexOrKey(String value); /** + * Handle contiguous []. + */ + void handleGenericInIterable(); + + /** * Return a result. Called after navigation is complete. * * @return result @@ -97,24 +102,28 @@ public class PathNavigation { public static T navigateAndReturn(String propertyPath, Callback callback) { try { StringTokenizer tokens = new StringTokenizer(StringUtils.defaultString(propertyPath), ".[]", true); - while (tokens.hasMoreTokens()) { - String token = tokens.nextToken(); - if (".".equals(token)) { - continue; + TokenType state = TokenType.START; + + String token = null; + while (state != TokenType.END) { + if (state == TokenType.KEY) { + callback.handleIndexOrKey(token); + } else if (state == TokenType.PROPERTY) { + callback.handleProperty(token); } - if ("[".equals(token)) { - String key = tokens.nextToken(); + TokenType next; + if (tokens.hasMoreTokens()) { token = tokens.nextToken(); - if (!"]".equals(token)) { - throw new ValidationException("']' missing, invalid property format: " + propertyPath); - } - callback.handleIndexOrKey(key); - continue; + next = state.parseNext(token); + } else { + next = TokenType.END; } - - // else, it is a property name - callback.handleProperty(token); + state.test(next); + if (state == TokenType.LBRACK && next == TokenType.RBRACK) { + callback.handleGenericInIterable(); + } + state = next; } return callback.result(); } catch (ValidationException ex) { @@ -124,4 +133,89 @@ public class PathNavigation { } } + private enum TokenType { + START("Expected property, index/key, or end of expression") { + @Override + boolean allowedNext(TokenType next) { + return next == PROPERTY || next == LBRACK || next == END; + } + }, + PROPERTY("Expected property path separator, index/key, or end of expression") { + @Override + boolean allowedNext(TokenType next) { + return next == DOT || next == LBRACK || next == END; + } + }, + LBRACK("Expected index/key or ]") { + @Override + boolean allowedNext(TokenType next) { + return next == RBRACK || next == KEY; + } + + /** + * {@inheritDoc} + */ + @Override + TokenType parseNext(String token) { + TokenType next = super.parseNext(token); + return next == PROPERTY ? KEY : next; + } + }, + KEY("Expected ]") { + @Override + boolean allowedNext(TokenType next) { + return next == RBRACK; + } + + }, + RBRACK("Expected property path separator or end of expression") { + @Override + boolean allowedNext(TokenType next) { + return next == DOT || next == END; + } + }, + DOT("Expected property after path separator") { + @Override + boolean allowedNext(TokenType next) { + return next == PROPERTY; + } + }, + END("") { + @Override + boolean allowedNext(TokenType next) { + return false; + } + }; + + final String violationMessage; + + /** + * @param violationMessage + * @param allowedNext + */ + private TokenType(String violationMessage) { + this.violationMessage = violationMessage; + } + + abstract boolean allowedNext(TokenType next); + + final void test(TokenType next) { + if (!allowedNext(next)) { + throw new IllegalStateException(violationMessage); + } + } + + TokenType parseNext(String token) { + if (".".equals(token)) { + return DOT; + } + if ("[".equals(token)) { + return LBRACK; + } + if ("]".equals(token)) { + return RBRACK; + } + return PROPERTY; + } + } } Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java Wed Sep 29 15:35:46 2010 @@ -75,4 +75,9 @@ public interface DynamicMetaGraphManager * {@link #forRead()} results. */ Interface writable(); + + /** + * Clear the dynamic metadata. + */ + void clear(); } Added: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java?rev=1002681&view=auto ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java (added) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java Wed Sep 29 15:35:46 2010 @@ -0,0 +1,538 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.bval.jsr303.dynamic; + +import static org.apache.bval.jsr303.dynamic.DynamicModel.copyConstraints; +import static org.apache.bval.jsr303.dynamic.DynamicModel.copyFeatures; +import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredContainer; +import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredProperty; +import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.DYNAMIC_CONSTRAINT_COLLECTION; +import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.META_CONTAINER; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.validation.Path; + +import org.apache.bval.MetaBeanFinder; +import org.apache.bval.jsr303.AnnotationProcessor; +import org.apache.bval.jsr303.AppendValidationToMeta; +import org.apache.bval.jsr303.UnknownPropertyException; +import org.apache.bval.jsr303.util.ClassHelper; +import org.apache.bval.jsr303.util.NodeImpl; +import org.apache.bval.jsr303.util.PathImpl; +import org.apache.bval.jsr303.util.PathNavigation; +import org.apache.bval.model.FeaturesCapable; +import org.apache.bval.model.MetaBean; +import org.apache.bval.model.MetaProperty; +import org.apache.bval.util.AccessStrategy; +import org.apache.bval.util.IndexedAccess; +import org.apache.bval.util.KeyedAccess; +import org.apache.bval.util.PropertyAccess; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.Pair; +import org.apache.commons.lang3.reflect.TypeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@link DynamicMetaGraphManager} implementation. + * + * @version $Rev$ $Date$ + */ +final class DynamicMetaGraphManagerImpl implements DynamicMetaGraphManager { + private static final Collection EMPTY_DYNAMIC_ANNOTATIONS = Collections. emptySet(); + + private static class FindType extends PathNavigation.CallbackProcedure { + Type type; + Class rawType; + + /** + * Create a new DynamicValidatorContext.GetRawType instance. + */ + public FindType(Class root) { + this.rawType = root; + } + + /** + * {@inheritDoc} + */ + public synchronized void handleProperty(String name) { + setType(new PropertyAccess(rawType, name).getJavaType()); + } + + /** + * {@inheritDoc} + */ + public void handleIndexOrKey(String value) { + handleGenericInIterable(); + } + + private synchronized void setType(Type type) { + this.rawType = TypeUtils.getRawType(type, this.type); + this.type = type; + } + + /** + * {@inheritDoc} + */ + public void handleGenericInIterable() { + Type elementType = KeyedAccess.getJavaElementType(type); + if (elementType == null) { + elementType = IndexedAccess.getJavaElementType(type); + } + if (elementType == null) { + throw new UnknownPropertyException(String.format("Cannot resolve index/key type of %s", type)); + } + setType(elementType); + } + + } + + /** + * PathNavigation callback for initial location of a property path. + */ + private class NavigateOrBuildGraph implements PathNavigation.Callback { + private MetaBean metaBean; + private MetaProperty property; + + /** + * Create a new SetupConstraintCallback instance. + * + * @param root + */ + NavigateOrBuildGraph(MetaBean root) { + super(); + this.metaBean = root; + } + + /** + * {@inheritDoc} + */ + public void handleIndexOrKey(String value) { + MetaContainer container = getContainer(); + if (Integer.class.equals(container.getIdType())) { + @SuppressWarnings("unchecked") + MetaContainer collection = (MetaContainer) container; + metaBean = collection.getElement(Integer.valueOf(value)); + } else if (Object.class.equals(container.getIdType())) { + @SuppressWarnings("unchecked") + MetaContainer map = (MetaContainer) container; + metaBean = map.getElement(value); + } else { + throw new IllegalStateException(String.format("Don't know how to handle container id type %s", + container.getIdType())); + } + property = null; + } + + /** + * {@inheritDoc} + */ + public void handleGenericInIterable() { + metaBean = getContainer().getPrototype(); + property = null; + } + + /** + * {@inheritDoc} + */ + public void handleProperty(String name) { + if (property != null) { + metaBean = property.getMetaBean(); + } + property = getRequiredProperty(metaBean, name); + } + + /** + * {@inheritDoc} + */ + public FeaturesCapable result() { + return property == null ? metaBean : property; + } + + private MetaContainer getContainer() { + return getRequiredContainer(property == null ? metaBean : property); + } + } + + final ThreadLocal currentValidationState = new ThreadLocal(); + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final DynamicMetaGraphManager.Interface writable = new DynamicMetaGraphManager.Interface() { + + /** + * {@inheritDoc} + */ + public MetaBean getMetaBean(Class type) { + MetaBean result; + if (dynamicBeanInfo.containsKey(type)) { + result = dynamicBeanInfo.get(type); + } else { + result = new MetaBean(); + result.setBeanClass(type); + MetaBean faster = dynamicBeanInfo.putIfAbsent(type, result); + if (faster != null) { + return faster; + } + } + return result; + } + + /** + * {@inheritDoc} + */ + public T getMeta(Class type, String propertyPath) { + MetaBean root = getMetaBean(type); + @SuppressWarnings("unchecked") + T result = (T) PathNavigation.navigateAndReturn(propertyPath, new NavigateOrBuildGraph(root)); + return result; + } + }; + + private final DynamicMetaGraphManager.Interface readOnly = new DynamicMetaGraphManager.Interface() { + /** + * {@inheritDoc} + */ + public MetaBean getMetaBean(Class type) { + final MetaBean initial = metaBeanFinder.findForClass(type); + MetaBean result = initial; + + final PathImpl path; + final Object rootBean; + final MetaBean rootMetaBean; + + DynamicValidationState validationState = currentValidationState.get(); + if (validationState == null) { + path = PathImpl.create(null); + rootBean = null; + rootMetaBean = initial; + } else { + rootMetaBean = validationState.getRootMetaBean(); + path = validationState.getPropertyPath(); + rootBean = validationState.getRootBean(); + } + try { + /* + * For each step of the path, we need to know whether the bean + * we are looking for matches a mapped property, so we build a + * stack of path/bean pairs. We use a stack so that when we + * process, the longest path goes last and therefore wins over + * short paths: the rationale here is that the longer path is + * more specific thus more likely to be rooted at more important + * part of your domain model. + */ + Deque>> pathStack = + buildPathStack(path, rootBean, rootMetaBean.getBeanClass()); + + while (!pathStack.isEmpty()) { + Pair> pair = pathStack.pop(); + List dynamicInfo = getAssignableDynamicInfo(pair.right); + + PathImpl relativePath = pair.left; + for (MetaBean root : dynamicInfo) { + MetaBean leaf = findLeaf(root, relativePath); + if (leaf == null) { + continue; + } + if (result == initial) { + result = initial.copy(); + } + + // copy bean + property features and constraints: + copyFeatures(result, leaf); + copyConstraints(result, leaf); + + for (MetaProperty sourceProperty : leaf.getProperties()) { + MetaProperty targetProperty = getRequiredProperty(result, sourceProperty.getName()); + copyFeatures(targetProperty, sourceProperty); + copyConstraints(targetProperty, sourceProperty); + } + + } + } + + if (result == initial) { + return result; + } + // now the dynamic constraints should FINALLY be fully + // populated: + + { + Collection constraints = + result.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS); + for (Annotation constraint : constraints) { + annotationProcessor.processAnnotation(constraint, result.getBeanClass(), + new AppendValidationToMeta(result)); + } + } + for (MetaProperty property : result.getProperties()) { + String propertyName = property.getName(); + Collection constraints = + property.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS); + for (Annotation constraint : constraints) { + annotationProcessor.processAnnotation(constraint, property, result.getBeanClass(), + new PropertyAccess(result.getBeanClass(), propertyName), new AppendValidationToMeta( + property)); + } + } + + } catch (Exception e) { + StringBuilder msg = + new StringBuilder("Encountered error applying dynamic constraints for type ") + .append(type.getName()); + if (!path.isRootPath()) { + msg.append(": path ").append(path); + } + log.error(msg.toString(), e); + } + return result; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + public T getMeta(Class type, String propertyPath) { + MetaBean rootMetaBean = metaBeanFinder.findForClass(type); + + PathImpl path = PathImpl.createPathFromString(propertyPath); + String propertyName; + NodeImpl leafNode = path.getLeafNode(); + if (!leafNode.isInIterable()) { + propertyName = leafNode.getName(); + path.removeLeafNode(); + } else { + propertyName = null; + } + FindType findType = new FindType(type); + PathNavigation.navigate(path.toString(), findType); + Class beanType = findType.rawType; + + FeaturesCapable result; + try { + currentValidationState.set(new DynamicValidationStateBean(null, rootMetaBean, path)); + result = getMetaBean(beanType); + if (propertyName != null) { + result = ((MetaBean) result).getProperty(propertyName); + if (result == null) { + // build from its metabean + + findType = new FindType(beanType); + PathNavigation.navigateAndReturn(propertyName, findType); + MetaProperty prop = new MetaProperty(); + prop.setName(propertyName); + prop.setParentMetaBean((MetaBean) result); + prop.setType(findType.type); + + // replace the propertyName, but I doubt it matters + path.addNode(new NodeImpl(propertyName)); + MetaBean metaBean = getMetaBean(prop.getTypeClass()); + prop.setMetaBean(metaBean); + result = prop; + } + } + return (T) result; + } finally { + currentValidationState.remove(); + } + } + }; + + private final ConcurrentMap, MetaBean> dynamicBeanInfo = new ConcurrentHashMap, MetaBean>(); + private final AnnotationProcessor annotationProcessor; + private final MetaBeanFinder metaBeanFinder; + + // private String wildcard = DynamicValidatorContext.DEFAULT_WILDCARD; + + /** + * Create a new DynamicMetaGraphManagerImpl instance. + * + * @param annotationProcessor + * @param metaBeanFinder + */ + DynamicMetaGraphManagerImpl(AnnotationProcessor annotationProcessor, MetaBeanFinder metaBeanFinder) { + super(); + this.annotationProcessor = annotationProcessor; + this.metaBeanFinder = metaBeanFinder; + } + + /** + * {@inheritDoc} + */ + public Interface readOnly() { + return readOnly; + } + + /** + * {@inheritDoc} + */ + public Interface writable() { + return writable; + } + + /** + * {@inheritDoc} + */ + public void clear() { + dynamicBeanInfo.clear(); + } + + private List getAssignableDynamicInfo(Class type) { + List> classSequence = new ArrayList>(); + ClassHelper.fillFullClassHierarchyAsList(classSequence, type); + List result = new ArrayList(classSequence.size()); + for (Class assignable : classSequence) { + MetaBean dynamicInfo = dynamicBeanInfo.get(assignable); + if (dynamicInfo != null) { + result.add(dynamicInfo); + } + } + return result; + } + + private MetaBean findLeaf(MetaBean root, PathImpl path) { + if (path.isRootPath()) { + return root; + } + MetaBean metaBean = root; + MetaProperty property = null; + + // iterate over the path; bail at the first null meta object: + for (Path.Node node : path) { + if (node.getName() != null) { + property = metaBean.getProperty(node.getName()); + if (property == null) { + return null; + } + // make sure the source (dynamic) properties know how to + // cascade so that when/if they copy over the target will + // cascade them as well: + annotationProcessor.addAccessStrategy(property, + new PropertyAccess(metaBean.getBeanClass(), node.getName())); + + metaBean = property.getMetaBean(); + } + if (node.isInIterable()) { + FeaturesCapable tip = property == null ? metaBean : property; + MetaContainer container = tip.getFeature(META_CONTAINER); + if (container == null) { + return null; + } + if (container.getIdType().equals(Integer.class)) { + @SuppressWarnings("unchecked") + MetaContainer coll = (MetaContainer) container; + metaBean = coll.getMergedElement(node.getIndex()); + } else { + @SuppressWarnings("unchecked") + MetaContainer map = (MetaContainer) container; + metaBean = map.getMergedElement(node.getKey()); + } + property = null; + } + } + return metaBean; + } + + /* + * build a stack of pairs of path + metabean representing each object in the + * currently known path, i.e. what we're trying to complete the bean for + */ + private static Deque>> buildPathStack(final PathImpl fullPath, Object rootBean, + Class rootType) { + // get a list of Nodes we can play with: + LinkedList nodes = new LinkedList(); + Iterator fullNodes = fullPath.iterator(); + while (fullNodes.hasNext()) { + nodes.add(fullNodes.next()); + } + + Deque>> stack = new ArrayDeque>>(); + + Class rawType = rootType; + Type type = rawType; + Object bean = rootBean; + + while (true) { + PathImpl path = buildPath(nodes); + stack.push(Pair.> of(path, rawType)); + if (path.isRootPath()) { + break; + } + // handle the property: + Path.Node node = nodes.remove(0); + if (node.getName() != null) { + PropertyAccess access = new PropertyAccess(rawType, node.getName()); + if (bean != null) { + bean = access.get(bean); + } + rawType = TypeUtils.getRawType(access.getJavaType(), type); + type = access.getJavaType(); + if (node.isInIterable()) { + //substitute a nameless indexed property node and repeat the loop: + NodeImpl sub = new NodeImpl(null); + sub.setInIterable(true); + if (IndexedAccess.getJavaElementType(type) != null) { + sub.setIndex(node.getIndex()); + } else if (KeyedAccess.getJavaElementType(type) != null) { + sub.setKey(node.getKey()); + } + nodes.add(0, sub); + continue; + } + } + if (node.isInIterable()) { + AccessStrategy access; + if (IndexedAccess.getJavaElementType(type) != null) { + access = + new IndexedAccess(type, ObjectUtils.defaultIfNull(node.getIndex(), Integer.valueOf(-1)) + .intValue()); + } else if (KeyedAccess.getJavaElementType(type) != null) { + access = new KeyedAccess(type, node.getKey()); + } else { + throw new UnknownPropertyException(String.format("%s in %s", node, path)); + } + if (bean != null) { + bean = access.get(bean); + } + rawType = TypeUtils.getRawType(access.getJavaType(), type); + type = access.getJavaType(); + } + } + return stack; + } + + private static PathImpl buildPath(Iterable nodes) { + PathImpl result = PathImpl.create(null); + for (Path.Node node : nodes) { + result.addNode(node); + } + return result; + } + +} Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java Wed Sep 29 15:35:46 2010 @@ -20,6 +20,7 @@ import static org.apache.bval.jsr303.dyn import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -116,23 +117,23 @@ public class DynamicModel { /** * Get or create a MetaContainer for the specified property. * - * @param property + * @param meta * @return MetaContainer * @throws IllegalArgumentException * if the property doesn't seem to refer to a container */ - public static MetaContainer getRequiredContainer(MetaProperty property) { - MetaContainer result = property.getFeature(META_CONTAINER); + public static MetaContainer getRequiredContainer(FeaturesCapable meta) { + MetaContainer result = meta.getFeature(META_CONTAINER); + Type type = meta instanceof MetaProperty ? ((MetaProperty) meta).getType() : ((MetaBean) meta).getBeanClass(); if (result == null) { - if (KeyedAccess.getJavaElementType(property.getType()) != null) { - result = new MetaMap(property); - } else if (IndexedAccess.getJavaElementType(property.getType()) != null) { - result = new MetaCollection(property); + if (KeyedAccess.getJavaElementType(type) != null) { + result = new MetaMap(type); + } else if (IndexedAccess.getJavaElementType(type) != null) { + result = new MetaCollection(type); } else { - throw new IllegalArgumentException("don't know how to make a container of " + property + " of " - + property.getParentMetaBean()); + throw new IllegalArgumentException(String.format("don't know how to make a container of %s", meta)); } - property.putFeature(META_CONTAINER, result); + meta.putFeature(META_CONTAINER, result); } return result; } Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java Wed Sep 29 15:35:46 2010 @@ -16,28 +16,11 @@ */ package org.apache.bval.jsr303.dynamic; -import static org.apache.bval.jsr303.dynamic.DynamicModel.copyConstraints; -import static org.apache.bval.jsr303.dynamic.DynamicModel.copyFeatures; -import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredContainer; -import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredDynamicConstraints; -import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredProperty; -import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.DYNAMIC_CONSTRAINT_COLLECTION; -import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.META_CONTAINER; +import static org.apache.bval.jsr303.dynamic.DynamicModel.*; import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import javax.validation.Path; import javax.validation.Validator; import javax.validation.ValidatorContext; @@ -46,384 +29,70 @@ import org.apache.bval.MetaBeanFinder; import org.apache.bval.MetaBeanManager; import org.apache.bval.jsr303.AnnotationProcessor; import org.apache.bval.jsr303.ApacheFactoryContext; -import org.apache.bval.jsr303.AppendValidationToMeta; -import org.apache.bval.jsr303.UnknownPropertyException; -import org.apache.bval.jsr303.util.ClassHelper; -import org.apache.bval.jsr303.util.PathImpl; -import org.apache.bval.jsr303.util.PathNavigation; import org.apache.bval.model.FeaturesCapable; import org.apache.bval.model.MetaBean; -import org.apache.bval.model.MetaProperty; -import org.apache.bval.util.AccessStrategy; -import org.apache.bval.util.IndexedAccess; -import org.apache.bval.util.KeyedAccess; -import org.apache.bval.util.PropertyAccess; -import org.apache.commons.lang3.Pair; -import org.apache.commons.lang3.reflect.TypeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * {@link ValidatorContext} implementation supporting context-bound dynamic * constraints. - * + * * @version $Rev$ $Date$ */ public class DynamicValidatorContext extends ApacheFactoryContext implements DynamicMetaGraphManager { - /** - * Default means of signifying "any" as a match for a bracketed index/key in - * a path. - */ - public static final String DEFAULT_WILDCARD = "*"; - - private static final Collection EMPTY_DYNAMIC_ANNOTATIONS = Collections. emptySet(); - - private class GetRawType implements PathNavigation.Callback> { - private Type type; - private Class rawType; - /** - * Create a new DynamicValidatorContext.GetRawType instance. - */ - public GetRawType(Class root) { - this.rawType = root; - } + private class DynamicMetaBeanFinder extends MetaBeanManager { - /** - * {@inheritDoc} - */ - public synchronized void handleProperty(String name) { - setType(new PropertyAccess(rawType, name).getJavaType()); - } + final MetaBeanFinder staticFinder = new MetaBeanFinder() { - /** - * {@inheritDoc} - */ - public void handleIndexOrKey(String value) { - Type elementType = KeyedAccess.getJavaElementType(type); - if (elementType == null) { - elementType = IndexedAccess.getJavaElementType(type); + public MetaBean findForId(String beanInfoId) { + return DynamicMetaBeanFinder.this.findForId(beanInfoId); } - if (elementType == null) { - throw new UnknownPropertyException(String.format( - "Cannot resolve index/key %s in property path expression", value)); - } - setType(elementType); - } - - private synchronized void setType(Type type) { - this.rawType = TypeUtils.getRawType(type, this.type); - this.type = type; - } - - /** - * {@inheritDoc} - */ - public Class result() { - return rawType; - } - - } - /** - * PathNavigation callback for initial location of a property path. - */ - private class NavigateOrBuildGraph implements PathNavigation.Callback { - private MetaBean metaBean; - private MetaProperty property; + public MetaBean findForClass(Class clazz) { + return findStatic(clazz); + } + }; - /** - * Create a new SetupConstraintCallback instance. - * - * @param root - */ - NavigateOrBuildGraph(MetaBean root) { - super(); - this.metaBean = root; - } + final DynamicMetaGraphManagerImpl metaGraphManager; /** - * {@inheritDoc} + * Create a new DynamicValidatorContext.DynamicMetaBeanFinder instance. */ - public void handleIndexOrKey(String value) { - if (property == null) { - throw new IllegalStateException( - "Bean validation doesn't handle property paths that lead with indexes... does it?"); - } - MetaContainer container = getRequiredContainer(property); - if (wildcard.equals(value)) { - metaBean = container.getPrototype(); - } else if (Integer.class.equals(container.getIdType())) { - @SuppressWarnings("unchecked") - MetaContainer collection = (MetaContainer) container; - metaBean = collection.getElement(Integer.valueOf(value)); - } else if (Object.class.equals(container.getIdType())) { - @SuppressWarnings("unchecked") - MetaContainer map = (MetaContainer) container; - metaBean = map.getElement(value); - } else { - throw new IllegalStateException(String.format("Don't know how to handle container id type %s", - container.getIdType())); - } - property = null; + public DynamicMetaBeanFinder(MetaBeanBuilder builder) { + super(builder); + this.metaGraphManager = + new DynamicMetaGraphManagerImpl(new AnnotationProcessor(DynamicValidatorContext.this), staticFinder); } - /** - * {@inheritDoc} - */ - public void handleProperty(String name) { - if (property != null) { - metaBean = property.getMetaBean(); - } - property = getRequiredProperty(metaBean, name); + private MetaBean findStatic(Class clazz) { + return super.findForClass(clazz); } /** * {@inheritDoc} */ - public FeaturesCapable result() { - return property == null ? metaBean : property; - } - - } - - private class DynamicMetaBeanFinder extends MetaBeanManager { - - /** - * Create a new DynamicValidatorContext.DynamicMetaBeanFinder instance. - */ - DynamicMetaBeanFinder(MetaBeanBuilder builder) { - super(builder); + public MetaBean findForClass(final Class clazz) { + return metaGraphManager.readOnly().getMetaBean(clazz); } /** * {@inheritDoc} */ - public MetaBean findForClass(final Class clazz) { - final MetaBean initial = super.findForClass(clazz); - MetaBean result = initial; - - final PathImpl path; - final Object rootBean; - final MetaBean rootMetaBean; - - DynamicValidationState validationState = currentValidationState.get(); - if (validationState == null) { - path = PathImpl.create(null); - rootBean = null; - rootMetaBean = initial; - } else { - rootMetaBean = validationState.getRootMetaBean(); - path = validationState.getPropertyPath(); - rootBean = validationState.getRootBean(); - } - try { - /* - * For each step of the path, we need to know whether the bean - * we are looking for matches a mapped property, so we build a - * stack of path/bean pairs. We use a stack so that when we - * process, the longest path goes last and therefore wins over - * short paths: the rationale here is that the longer path is - * more specific thus more likely to be rooted at more important - * part of your domain model. - */ - Deque>> pathStack = - buildPathStack(path, rootBean, rootMetaBean.getBeanClass()); - - while (!pathStack.isEmpty()) { - Pair> pair = pathStack.pop(); - List dynamicInfo = getAssignableDynamicInfo(pair.right); - - PathImpl relativePath = pair.left; - for (MetaBean root : dynamicInfo) { - MetaBean leaf = findLeaf(root, relativePath); - if (leaf == null) { - continue; - } - if (result == initial) { - result = initial.copy(); - } - - // copy bean + property features and constraints: - copyFeatures(result, leaf); - copyConstraints(result, leaf); - - for (MetaProperty sourceProperty : leaf.getProperties()) { - MetaProperty targetProperty = getRequiredProperty(result, sourceProperty.getName()); - copyFeatures(targetProperty, sourceProperty); - copyConstraints(targetProperty, sourceProperty); - } - - } - } - - if (result == initial) { - return result; - } - // now the dynamic constraints should FINALLY be fully - // populated: - - { - Collection constraints = - result.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS); - for (Annotation constraint : constraints) { - annotationProcessor.processAnnotation(constraint, result.getBeanClass(), - new AppendValidationToMeta(result)); - } - } - for (MetaProperty property : result.getProperties()) { - String propertyName = property.getName(); - Collection constraints = - property.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS); - for (Annotation constraint : constraints) { - annotationProcessor.processAnnotation(constraint, property, result.getBeanClass(), - new PropertyAccess(result.getBeanClass(), propertyName), new AppendValidationToMeta( - property)); - } - } - - } catch (Exception e) { - StringBuilder msg = - new StringBuilder("Encountered error applying dynamic constraints for type ").append(clazz - .getName()); - if (!path.isRootPath()) { - msg.append(": path ").append(path); - } - log.error(msg.toString(), e); - } - return result; - } - } - - private List getAssignableDynamicInfo(Class type) { - List> classSequence = new ArrayList>(); - ClassHelper.fillFullClassHierarchyAsList(classSequence, type); - List result = new ArrayList(classSequence.size()); - for (Class assignable : classSequence) { - MetaBean dynamicInfo = dynamicBeanInfo.get(assignable); - if (dynamicInfo != null) { - result.add(dynamicInfo); - } - } - return result; - } - - /* - * build a stack of pairs of path + metabean representing each object in the - * currently known path, i.e. what we're trying to complete the bean for - */ - private Deque>> buildPathStack(final PathImpl fullPath, Object rootBean, - Class rootType) { - // get a list of Nodes we can play with: - LinkedList nodes = new LinkedList(); - Iterator fullNodes = fullPath.iterator(); - while (fullNodes.hasNext()) { - nodes.add(fullNodes.next()); + public MetaBean findForId(String beanInfoId) { + return super.findForId(beanInfoId); } - - Deque>> stack = new ArrayDeque>>(); - - PathImpl path = fullPath; - Class rawType = rootType; - Type type = rawType; - Object bean = rootBean; - - while (true) { - stack.push(Pair.> of(path, rawType)); - if (path.isRootPath()) { - break; - } - // handle the property: - Path.Node node = nodes.remove(0); - { - PropertyAccess access = new PropertyAccess(rawType, node.getName()); - if (bean != null) { - bean = access.get(bean); - } - rawType = TypeUtils.getRawType(access.getJavaType(), type); - type = access.getJavaType(); - } - if (node.isInIterable()) { - AccessStrategy access; - if (node.getIndex() != null) { - access = new IndexedAccess(type, node.getIndex()); - } else { - access = new KeyedAccess(type, node.getKey()); - } - if (bean != null) { - bean = access.get(bean); - } - rawType = TypeUtils.getRawType(access.getJavaType(), type); - type = access.getJavaType(); - } - - // rebuild relative path from remaining nodes: - path = buildPath(nodes); - } - return stack; } - private MetaBean findLeaf(MetaBean root, PathImpl path) { - if (path.isRootPath()) { - return root; - } - MetaBean result = root; - // iterate over the path; bail at the first null meta object: - for (Path.Node node : path) { - MetaProperty sourceProperty = result.getProperty(node.getName()); - if (sourceProperty == null) { - return null; - } - if (node.isInIterable()) { - if (sourceProperty.getFeature(META_CONTAINER) == null) { - return null; - } - if (node.getIndex() != null) { - MetaContainer collection = sourceProperty.getFeature(META_CONTAINER); - result = collection.getMergedElement(node.getIndex()); - } else { - // assume there must be a key - MetaContainer map = sourceProperty.getFeature(META_CONTAINER); - result = map.getMergedElement(node.getKey()); - } - } else { - result = sourceProperty.getMetaBean(); - } - // make sure the source (dynamic) properties know how to - // cascade so that when/if they copy over the target will - // cascade them as well: - annotationProcessor.addAccessStrategy(sourceProperty, new PropertyAccess(sourceProperty.getParentMetaBean() - .getBeanClass(), sourceProperty.getName())); - } - return result; - } - - private final Logger log = LoggerFactory.getLogger(getClass()); - private final ThreadLocal currentValidationState = - new ThreadLocal(); - - private final AnnotationProcessor annotationProcessor = new AnnotationProcessor(this); - private final ConcurrentMap, MetaBean> dynamicBeanInfo = new ConcurrentHashMap, MetaBean>(); - private String wildcard = DEFAULT_WILDCARD; + private final DynamicMetaGraphManagerImpl metaGraphManager; /** * Create a new {@link DynamicValidatorContext} instance. - * + * * @param validatorFactory */ public DynamicValidatorContext(DynamicValidatorFactory validatorFactory) { super(validatorFactory); - } - - /** - * Set the wildcard string in use for dynamically constrained properties. - * - * @param wildcard - * @return this following the chained invocation pattern - */ - public DynamicValidatorContext wildcard(String wildcard) { - this.wildcard = wildcard; - return this; + this.metaGraphManager = ((DynamicMetaBeanFinder) getMetaBeanFinder()).metaGraphManager; } /** @@ -436,7 +105,7 @@ public class DynamicValidatorContext ext /** * Constrain a bean type at the class level. - * + * * @param beanType * @param constraintCollectionManipulator * @return this following the chained invocation pattern @@ -448,106 +117,38 @@ public class DynamicValidatorContext ext /** * Constrain a property path relative to a root bean type. - * + * * @param beanType * @param propertyPath * @param constraintCollectionManipulator * @return this following the chained invocation pattern */ public DynamicValidatorContext constrain(Class beanType, String propertyPath, Annotation constraint) { - MetaBean metaBean = writable().getMetaBean(beanType); - FeaturesCapable meta = PathNavigation.navigateAndReturn(propertyPath, new NavigateOrBuildGraph(metaBean)); + FeaturesCapable meta = writable().getMeta(beanType, propertyPath); Collection constraints = getRequiredDynamicConstraints(meta); ConstraintAppender.FACTORY.constraintAppender(constraint).append(constraint, constraints); return this; } /** - * Clear dynamic constraints for this context. + * {@inheritDoc} */ - public void clearDynamicConstraints() { - dynamicBeanInfo.clear(); + public DynamicMetaGraphManager.Interface writable() { + return metaGraphManager.writable(); } /** * {@inheritDoc} */ - public DynamicMetaGraphManager.Interface writable() { - return new DynamicMetaGraphManager.Interface() { - - /** - * {@inheritDoc} - */ - public MetaBean getMetaBean(Class type) { - MetaBean result; - if (dynamicBeanInfo.containsKey(type)) { - result = dynamicBeanInfo.get(type); - } else { - result = new MetaBean(); - result.setBeanClass(type); - MetaBean faster = dynamicBeanInfo.putIfAbsent(type, result); - if (faster != null) { - return faster; - } - } - return result; - } - - /** - * {@inheritDoc} - */ - public T getMeta(Class type, String propertyPath) { - MetaBean root = getMetaBean(type); - @SuppressWarnings("unchecked") - T result = (T) PathNavigation.navigateAndReturn(propertyPath, new NavigateOrBuildGraph(root)); - return result; - } - }; + public DynamicMetaGraphManager.Interface readOnly() { + return metaGraphManager.readOnly(); } /** * {@inheritDoc} */ - public DynamicMetaGraphManager.Interface readOnly() { - return new DynamicMetaGraphManager.Interface() { - - /** - * {@inheritDoc} - */ - public MetaBean getMetaBean(Class type) { - return getMetaBeanFinder().findForClass(type); - } - - /** - * {@inheritDoc} - */ - @SuppressWarnings("unchecked") - public T getMeta(Class type, String propertyPath) { - MetaBean rootMetaBean = DynamicValidatorContext.this.writable().getMetaBean(type); - PathImpl path = PathImpl.createPathFromString(propertyPath); - // trim off simple leaf property if applicable: - String simplePropertyName; - if (path.isRootPath() || path.getLeafNode().isInIterable()) { - simplePropertyName = null; - } else { - simplePropertyName = path.getLeafNode().getName(); - path = path.getPathWithoutLeafNode(); - } - Class beanClass = PathNavigation.navigateAndReturn(path.toString(), new GetRawType(type)); - - FeaturesCapable meta; - try { - register(new DynamicValidationStateBean(null, rootMetaBean, path)); - meta = getMetaBeanFinder().findForClass(beanClass); - } finally { - clearValidationState(); - } - if (simplePropertyName != null) { - meta = ((MetaBean) meta).getProperty(simplePropertyName); - } - return (T) meta; - } - }; + public void clear() { + metaGraphManager.clear(); } /** @@ -562,26 +163,19 @@ public class DynamicValidatorContext ext * Register a {@link DynamicValidationState} instance to the current thread. * Etiquette requires the caller to clear the instance when no longer * needed. - * + * * @param validationState * @see #clearValidationState() */ void register(DynamicValidationState validationState) { - currentValidationState.set(validationState); + metaGraphManager.currentValidationState.set(validationState); } /** * Clear the registered {@link DynamicValidationState}. */ void clearValidationState() { - currentValidationState.remove(); + metaGraphManager.currentValidationState.remove(); } - private static PathImpl buildPath(Iterable nodes) { - PathImpl result = PathImpl.create(null); - for (Path.Node node : nodes) { - result.addNode(node); - } - return result; - } } Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java Wed Sep 29 15:35:46 2010 @@ -18,7 +18,6 @@ package org.apache.bval.jsr303.dynamic; import java.lang.reflect.Type; -import org.apache.bval.model.MetaProperty; import org.apache.bval.util.IndexedAccess; /** @@ -33,15 +32,15 @@ public class MetaCollection extends Meta * * @param parent */ - public MetaCollection(MetaProperty parent) { - super(Integer.class, parent); + public MetaCollection(Type type) { + super(Integer.class, type); } /** * {@inheritDoc} */ @Override - protected Type getElementType(MetaProperty parent) { - return IndexedAccess.getJavaElementType(parent.getType()); + protected Type getElementType(Type type) { + return IndexedAccess.getJavaElementType(type); } } Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java Wed Sep 29 15:35:46 2010 @@ -23,7 +23,6 @@ import java.util.concurrent.ConcurrentHa import java.util.concurrent.ConcurrentMap; import org.apache.bval.model.MetaBean; -import org.apache.bval.model.MetaProperty; import org.apache.commons.lang3.reflect.TypeUtils; /** @@ -42,19 +41,19 @@ public abstract class MetaContainer { * Create a new MetaContainer instance. * @param parent */ - protected MetaContainer(Class idType, MetaProperty parent) { + protected MetaContainer(Class idType, Type type) { this.idType = idType; - this.elementType = getElementType(parent); + this.elementType = getElementType(type); prototype = new MetaBean(); - prototype.setBeanClass(TypeUtils.getRawType(elementType, parent.getType())); + prototype.setBeanClass(TypeUtils.getRawType(elementType, type)); } /** - * Get the raw element type of this {@link MetaContainer} given its parent. - * @param parent - * @return + * Get the element type of a container of type type. + * @param type + * @return Type */ - protected abstract Type getElementType(MetaProperty parent); + protected abstract Type getElementType(Type type); /** * @return the idType @@ -92,6 +91,9 @@ public abstract class MetaContainer { * @return MetaBean */ public MetaBean getElement(K id) { + if (id == null) { + return getPrototype(); + } MetaBean result = elements.get(id); if (result == null) { result = new MetaBean(); @@ -114,7 +116,9 @@ public abstract class MetaContainer { public MetaBean getMergedElement(K id) { MetaBean result = new MetaBean(); copy(result, prototype); - copy(result, elements.get(id)); + if (id != null) { + copy(result, elements.get(id)); + } return result; } Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java?rev=1002681&r1=1002680&r2=1002681&view=diff ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java (original) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java Wed Sep 29 15:35:46 2010 @@ -18,7 +18,6 @@ package org.apache.bval.jsr303.dynamic; import java.lang.reflect.Type; -import org.apache.bval.model.MetaProperty; import org.apache.bval.util.KeyedAccess; /** @@ -33,15 +32,15 @@ public class MetaMap extends MetaContain * * @param parent */ - public MetaMap(MetaProperty parent) { - super(Object.class, parent); + public MetaMap(Type type) { + super(Object.class, type); } /** * {@inheritDoc} */ @Override - protected Type getElementType(MetaProperty parent) { - return KeyedAccess.getJavaElementType(parent.getType()); + protected Type getElementType(Type type) { + return KeyedAccess.getJavaElementType(type); } } Added: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java?rev=1002681&view=auto ============================================================================== --- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java (added) +++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java Wed Sep 29 15:35:46 2010 @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.bval.jsr303.dynamic; + +import static org.junit.Assert.*; + +import javax.validation.Validation; + +import org.apache.bval.jsr303.ApacheValidationProvider; +import org.apache.bval.jsr303.ApacheValidatorConfiguration; +import org.apache.bval.jsr303.dynamic.DynamicMetaGraphManager; +import org.apache.bval.jsr303.dynamic.DynamicValidatorContext; +import org.apache.bval.jsr303.dynamic.DynamicValidatorFactory; +import org.apache.bval.jsr303.example.Book; +import org.apache.bval.model.MetaBean; +import org.junit.Before; +import org.junit.Test; + +/** + * Test the {@link DynamicMetaGraphManager} implementation of + * {@link DynamicValidatorContext}. + * + * @version $Rev$ $Date$ + */ +public class DynamicMetaGraphManagerTest { + + private DynamicMetaGraphManager metaGraphManager; + + @Before + public void setup() { + metaGraphManager = + Validation + .byProvider(ApacheValidationProvider.class) + .configure() + .addProperty(ApacheValidatorConfiguration.Properties.VALIDATOR_FACTORY_CLASSNAME, + DynamicValidatorFactory.class.getName()) + .addProperty(ApacheValidatorConfiguration.Properties.ENABLE_INTROSPECTOR, Boolean.TRUE.toString()) + .buildValidatorFactory().unwrap(DynamicValidatorFactory.class).usingContext(); + } + + @Test + public void testGetMetaBean() { + assertNotNull(metaGraphManager.writable().getMetaBean(Book.class)); + assertNotNull(metaGraphManager.readOnly().getMetaBean(Book.class)); + } + + @Test + public void testGetRootMeta() { + MetaBean metaBean = metaGraphManager.writable().getMeta(Book.class, ""); + assertNotNull(metaBean); + metaBean = metaGraphManager.readOnly().getMeta(Book.class, ""); + assertNotNull(metaBean); + } + + @Test + public void testGetImmediateProperty() { + assertNotNull(metaGraphManager.writable().getMeta(Book.class, "title")); + assertNotNull(metaGraphManager.readOnly().getMeta(Book.class, "title")); + } + + @Test + public void testGetNestedProperty() { + assertNotNull(metaGraphManager.writable().getMeta(Book.class, "author.addresses[].city")); + assertNotNull(metaGraphManager.readOnly().getMeta(Book.class, "author.addresses[].city")); + assertNotNull(metaGraphManager.readOnly().getMeta(Book.class, "author.addresses[0].city")); + } +} Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java ------------------------------------------------------------------------------ svn:eol-style = native