You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by mb...@apache.org on 2018/03/27 22:58:40 UTC

[2/2] bval git commit: use runtime type to find valueExtractor for container element keys

use runtime type to find valueExtractor for container element keys


Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/f69d9b97
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/f69d9b97
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/f69d9b97

Branch: refs/heads/bv2
Commit: f69d9b97398866f7b0348b52319b73b55da022ad
Parents: 85ea6c6
Author: Matt Benson <mb...@apache.org>
Authored: Tue Mar 27 17:58:23 2018 -0500
Committer: Matt Benson <mb...@apache.org>
Committed: Tue Mar 27 17:58:23 2018 -0500

----------------------------------------------------------------------
 .../jsr/descriptor/ContainerElementTypeD.java   | 44 +++++++++++++++++++-
 .../jsr/valueextraction/ValueExtractors.java    |  5 ++-
 2 files changed, 46 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bval/blob/f69d9b97/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
index ef00edc..fc97df8 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java
@@ -19,9 +19,13 @@
 package org.apache.bval.jsr.descriptor;
 
 import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Map;
 import java.util.stream.Stream;
 
 import javax.validation.ConstraintDeclarationException;
+import javax.validation.ValidationException;
 import javax.validation.metadata.ContainerElementTypeDescriptor;
 import javax.validation.valueextraction.ValueExtractor;
 
@@ -29,11 +33,19 @@ import org.apache.bval.jsr.GraphContext;
 import org.apache.bval.jsr.metadata.ContainerElementKey;
 import org.apache.bval.jsr.valueextraction.ExtractValues;
 import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.ObjectUtils;
 import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.TypeUtils;
 
 public class ContainerElementTypeD extends CascadableContainerD<CascadableContainerD<?, ?>, AnnotatedType>
     implements ContainerElementTypeDescriptor {
 
+    private static ContainerElementKey toContainerElementKey(TypeVariable<?> var) {
+        final Class<?> container = (Class<?>) var.getGenericDeclaration();
+        final int argIndex = ObjectUtils.indexOf(container.getTypeParameters(), var);
+        return new ContainerElementKey(container, Integer.valueOf(argIndex));
+    }
+
     private final ContainerElementKey key;
 
     ContainerElementTypeD(ContainerElementKey key, MetadataReader.ForContainer<AnnotatedType> reader,
@@ -58,11 +70,41 @@ public class ContainerElementTypeD extends CascadableContainerD<CascadableContai
 
     @Override
     protected Stream<GraphContext> readImpl(GraphContext context) throws Exception {
-        final ValueExtractor<?> valueExtractor = context.getValidatorContext().getValueExtractors().find(key);
+        final ContainerElementKey runtimeKey = runtimeKey(context.getValue());
+        final ValueExtractor<?> valueExtractor =
+            context.getValidatorContext().getValueExtractors().find(runtimeKey);
+
         if (valueExtractor == null) {
             Exceptions.raise(ConstraintDeclarationException::new, "No %s found for %s",
                 ValueExtractor.class.getSimpleName(), key);
         }
         return ExtractValues.extract(context, key, valueExtractor).stream();
     }
+
+    private ContainerElementKey runtimeKey(Object value) {
+        final Class<?> containerClass = key.getContainerClass();
+        final Class<? extends Object> runtimeType = value.getClass();
+        if (!runtimeType.equals(containerClass)) {
+            Exceptions.raiseUnless(containerClass.isAssignableFrom(runtimeType), ValidationException::new,
+                "Value %s is not assignment-compatible with %s", value, containerClass);
+
+            if (key.getTypeArgumentIndex() == null) {
+                return new ContainerElementKey(runtimeType, null);
+            }
+            final Map<TypeVariable<?>, Type> typeArguments = TypeUtils.getTypeArguments(runtimeType, containerClass);
+
+            Type type = typeArguments.get(containerClass.getTypeParameters()[key.getTypeArgumentIndex().intValue()]);
+
+            while (type instanceof TypeVariable<?>) {
+                final TypeVariable<?> var = (TypeVariable<?>) type;
+                final Type nextType = typeArguments.get(var);
+                if (nextType instanceof TypeVariable<?>) {
+                    type = nextType;
+                } else {
+                    return toContainerElementKey(var);
+                }
+            }
+        }
+        return key;
+    }
 }

http://git-wip-us.apache.org/repos/asf/bval/blob/f69d9b97/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
index ca45701..2ebc2c7 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
@@ -22,6 +22,7 @@ import java.lang.reflect.Type;
 import java.lang.reflect.WildcardType;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
@@ -223,8 +224,8 @@ public class ValueExtractors {
             return null;
         }
         final Map<ContainerElementKey, ValueExtractor<?>> candidateMap =
-            assignableKeys.stream().filter(allValueExtractors::containsKey)
-                .collect(Collectors.toMap(Function.identity(), allValueExtractors::get));
+            assignableKeys.stream().filter(allValueExtractors::containsKey).collect(
+                Collectors.toMap(Function.identity(), allValueExtractors::get, (quid, quo) -> quo, LinkedHashMap::new));
 
         if (candidateMap.isEmpty()) {
             return null;