Repository: bval Updated Branches: refs/heads/bv2 313512196 -> 7b915ca2a
ValueExtractors work for TCK and spec compliance Project: http://git-wip-us.apache.org/repos/asf/bval/repo Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/b2b1b246 Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/b2b1b246 Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/b2b1b246 Branch: refs/heads/bv2 Commit: b2b1b246133b8cb6636fa273575794e42541b802 Parents: 3135121 Author: Matt Benson <[email protected]> Authored: Mon Mar 26 17:44:09 2018 -0500 Committer: Matt Benson <[email protected]> Committed: Mon Mar 26 17:44:09 2018 -0500 ---------------------------------------------------------------------- .../apache/bval/jsr/ApacheValidatorFactory.java | 3 +- .../org/apache/bval/jsr/ConfigurationImpl.java | 4 +- .../jsr/valueextraction/ValueExtractors.java | 109 ++++++++++++------- .../main/java/org/apache/bval/util/Lazy.java | 6 + 4 files changed, 78 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/bval/blob/b2b1b246/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java index 40849ac..5e5118f 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java @@ -45,6 +45,7 @@ import org.apache.bval.jsr.metadata.MetadataBuilders; import org.apache.bval.jsr.metadata.MetadataSource; import org.apache.bval.jsr.util.AnnotationsManager; import org.apache.bval.jsr.valueextraction.ValueExtractors; +import org.apache.bval.jsr.valueextraction.ValueExtractors.OnDuplicateContainerElementKey; import org.apache.bval.util.CloseableAble; import org.apache.bval.util.reflection.Reflection; import org.apache.commons.weaver.privilizer.Privilizing; @@ -87,7 +88,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } private static ValueExtractors createBaseValueExtractors(ParticipantFactory participantFactory) { - final ValueExtractors result = new ValueExtractors(); + final ValueExtractors result = new ValueExtractors(OnDuplicateContainerElementKey.OVERWRITE); participantFactory.loadServices(ValueExtractor.class).forEach(result::add); return result; } http://git-wip-us.apache.org/repos/asf/bval/blob/b2b1b246/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java index d726d4c..20ac2f8 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConfigurationImpl.java @@ -135,7 +135,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur private final LazyParticipant<ClockProvider> clockProvider = new LazyParticipant<>(this::getDefaultClockProvider); - private final ValueExtractors bootstrapValueExtractors = new ValueExtractors(); + private final ValueExtractors bootstrapValueExtractors = ValueExtractors.EMPTY.createChild(); private final ValueExtractors valueExtractors = bootstrapValueExtractors.createChild(); private final Lazy<BootstrapConfiguration> bootstrapConfiguration = new Lazy<>(this::createBootstrapConfiguration); @@ -371,7 +371,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur @Override public Set<ValueExtractor<?>> getValueExtractors() { - return Collections.unmodifiableSet(new LinkedHashSet<>(valueExtractors.getLocalValueExtractors().values())); + return Collections.unmodifiableSet(new LinkedHashSet<>(valueExtractors.getValueExtractors().values())); } public void deferBootstrapOverrides() { http://git-wip-us.apache.org/repos/asf/bval/blob/b2b1b246/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 00577e3..a99cd3d 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 @@ -26,7 +26,9 @@ import java.util.Map; import java.util.Optional; import java.util.Properties; import java.util.Set; +import java.util.TreeMap; import java.util.function.BooleanSupplier; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; @@ -52,38 +54,39 @@ import org.apache.bval.util.reflection.TypeUtils; * {@link ValueExtractor} collection of some level of a bean validation hierarchy. */ public class ValueExtractors { - public static final ValueExtractors DEFAULT; + public enum OnDuplicateContainerElementKey { + EXCEPTION, OVERWRITE; + } + + public static final ValueExtractors EMPTY = + new ValueExtractors(null, OnDuplicateContainerElementKey.EXCEPTION, Collections.emptyMap()); + public static final ValueExtractors DEFAULT; static { - DEFAULT = new ValueExtractors(null) { - { - final Properties defaultExtractors = new Properties(); - try { - defaultExtractors.load(ValueExtractors.class.getResourceAsStream("DefaultExtractors.properties")); - } catch (IOException e) { - throw new IllegalStateException(e); - } - split(defaultExtractors.getProperty(ValueExtractor.class.getName())).map(cn -> { - try { - @SuppressWarnings("unchecked") - final Class<? extends ValueExtractor<?>> result = - (Class<? extends ValueExtractor<?>>) Reflection.toClass(cn) - .asSubclass(ValueExtractor.class); - return result; - } catch (Exception e) { - throw new IllegalStateException(e); - } - }).map(ValueExtractors::newInstance).forEach(super::add); - - split(defaultExtractors.getProperty(ValueExtractor.class.getName() + ".container")) - .flatMap(ValueExtractors::loadValueExtractors).forEach(super::add); + final Properties defaultExtractors = new Properties(); + try { + defaultExtractors.load(ValueExtractors.class.getResourceAsStream("DefaultExtractors.properties")); + } catch (IOException e) { + throw new IllegalStateException(e); + } + final Map<ContainerElementKey, ValueExtractor<?>> m = new TreeMap<>(); + final Consumer<ValueExtractor<?>> put = ve -> m.put(ContainerElementKey.forValueExtractor(ve), ve); + + split(defaultExtractors.getProperty(ValueExtractor.class.getName())).map(cn -> { + try { + @SuppressWarnings("unchecked") + final Class<? extends ValueExtractor<?>> result = + (Class<? extends ValueExtractor<?>>) Reflection.toClass(cn).asSubclass(ValueExtractor.class); + return result; + } catch (Exception e) { + throw new IllegalStateException(e); } + }).map(ValueExtractors::newInstance).forEach(put); - @Override - public void add(ValueExtractor<?> extractor) { - throw new UnsupportedOperationException(); - } - }; + split(defaultExtractors.getProperty(ValueExtractor.class.getName() + ".container")) + .flatMap(ValueExtractors::loadValueExtractors).forEach(put); + + DEFAULT = new ValueExtractors(null, OnDuplicateContainerElementKey.EXCEPTION, Collections.unmodifiableMap(m)); } public static Class<?> getExtractedType(ValueExtractor<?> extractor, Type target) { @@ -152,32 +155,56 @@ public class ValueExtractors { return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1); } - private final Lazy<Map<ContainerElementKey, ValueExtractor<?>>> valueExtractors = new Lazy<>(HashMap::new); private final ValueExtractors parent; + private final Lazy<Map<ContainerElementKey, ValueExtractor<?>>> valueExtractors = new Lazy<>(TreeMap::new); + private final OnDuplicateContainerElementKey onDuplicateContainerElementKey; public ValueExtractors() { - this(DEFAULT); + this(OnDuplicateContainerElementKey.EXCEPTION); + } + + public ValueExtractors(OnDuplicateContainerElementKey onDuplicateContainerElementKey) { + this(DEFAULT, Validate.notNull(onDuplicateContainerElementKey)); } - private ValueExtractors(ValueExtractors parent) { + private ValueExtractors(ValueExtractors parent, OnDuplicateContainerElementKey onDuplicateContainerElementKey) { this.parent = parent; + this.onDuplicateContainerElementKey = onDuplicateContainerElementKey; + } + + private ValueExtractors(ValueExtractors parent, OnDuplicateContainerElementKey onDuplicateContainerElementKey, + Map<ContainerElementKey, ValueExtractor<?>> backingMap) { + this(parent, onDuplicateContainerElementKey); + this.valueExtractors.reset(backingMap); } public ValueExtractors createChild() { - return new ValueExtractors(this); + return createChild(OnDuplicateContainerElementKey.EXCEPTION); } - public void add(ValueExtractor<?> extractor) { - Validate.notNull(extractor); - valueExtractors.get().compute(ContainerElementKey.forValueExtractor(extractor), (k, v) -> { - Exceptions.raiseIf(v != null, ValueExtractorDeclarationException::new, - "Multiple context-level %ss specified for %s", f -> f.args(ValueExtractor.class.getSimpleName(), k)); - return extractor; - }); + public ValueExtractors createChild(OnDuplicateContainerElementKey onDuplicateContainerElementKey) { + return new ValueExtractors(this, onDuplicateContainerElementKey); } - public Map<ContainerElementKey, ValueExtractor<?>> getLocalValueExtractors() { - return valueExtractors.optional().map(Collections::unmodifiableMap).orElseGet(Collections::emptyMap); + public void add(ValueExtractor<?> extractor) { + Validate.notNull(extractor); + final ContainerElementKey key = ContainerElementKey.forValueExtractor(extractor); + if (key == null) { + Exceptions.raise(IllegalStateException::new, "Computed null %s for %s", + ContainerElementKey.class.getSimpleName(), extractor); + } + final Map<ContainerElementKey, ValueExtractor<?>> m = valueExtractors.get(); + if (onDuplicateContainerElementKey == OnDuplicateContainerElementKey.EXCEPTION) { + synchronized (this) { + if (m.containsKey(key)) { + Exceptions.raise(ValueExtractorDeclarationException::new, + "Multiple context-level %ss specified for %s", ValueExtractor.class.getSimpleName(), key); + } + m.put(key, extractor); + } + } else { + m.put(key, extractor); + } } public Map<ContainerElementKey, ValueExtractor<?>> getValueExtractors() { http://git-wip-us.apache.org/repos/asf/bval/blob/b2b1b246/bval-jsr/src/main/java/org/apache/bval/util/Lazy.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/util/Lazy.java b/bval-jsr/src/main/java/org/apache/bval/util/Lazy.java index 4796de3..fbc885b 100644 --- a/bval-jsr/src/main/java/org/apache/bval/util/Lazy.java +++ b/bval-jsr/src/main/java/org/apache/bval/util/Lazy.java @@ -39,6 +39,12 @@ public class Lazy<T> implements Supplier<T> { return this; } + public synchronized Lazy<T> reset(T value) { + this.value = value; + this.init = null; + return this; + } + @Override public T get() { if (init != null) {
