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/23 14:57:41 UTC
[4/4] bval git commit: refactor 'participant' object creation logic
to support CDI-injectable service loader based ValueExtractors (abstracted
for future implementation-specific use)
refactor 'participant' object creation logic to support CDI-injectable service loader based ValueExtractors (abstracted for future implementation-specific use)
Project: http://git-wip-us.apache.org/repos/asf/bval/repo
Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/4fd0140f
Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/4fd0140f
Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/4fd0140f
Branch: refs/heads/bv2
Commit: 4fd0140fd68856bc0dcdc7f22e9c60b37fce2a87
Parents: d781216
Author: Matt Benson <mb...@apache.org>
Authored: Fri Mar 23 09:57:29 2018 -0500
Committer: Matt Benson <mb...@apache.org>
Committed: Fri Mar 23 09:57:29 2018 -0500
----------------------------------------------------------------------
.../apache/bval/jsr/ApacheValidatorFactory.java | 43 +++++---
.../org/apache/bval/jsr/ConfigurationImpl.java | 81 ++++++--------
.../org/apache/bval/jsr/ParticipantFactory.java | 107 +++++++++++++++++++
.../org/apache/bval/util/CloseableAble.java | 27 +++++
4 files changed, 197 insertions(+), 61 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/bval/blob/4fd0140f/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 528e543..35b2919 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
@@ -35,12 +35,14 @@ import javax.validation.ValidationException;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.spi.ConfigurationState;
+import javax.validation.valueextraction.ValueExtractor;
import org.apache.bval.jsr.descriptor.DescriptorManager;
import org.apache.bval.jsr.metadata.MetadataBuilders;
import org.apache.bval.jsr.util.AnnotationsManager;
import org.apache.bval.jsr.valueextraction.ValueExtractors;
import org.apache.bval.jsr.xml.ValidationMappingParser;
+import org.apache.bval.util.CloseableAble;
import org.apache.bval.util.reflection.Reflection;
import org.apache.commons.weaver.privilizer.Privilizing;
import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
@@ -55,19 +57,6 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
private static volatile ApacheValidatorFactory DEFAULT_FACTORY;
- private MessageInterpolator messageResolver;
- private TraversableResolver traversableResolver;
- private ConstraintValidatorFactory constraintValidatorFactory;
- private ParameterNameProvider parameterNameProvider;
- private ClockProvider clockProvider;
- private final Map<String, String> properties;
- private final AnnotationsManager annotationsManager;
- private final DescriptorManager descriptorManager = new DescriptorManager(this);
- private final MetadataBuilders metadataBuilders = new MetadataBuilders();
- private final ValueExtractors valueExtractors = new ValueExtractors();
- private final ConstraintCached constraintsCache = new ConstraintCached();
- private final Collection<Closeable> toClose = new ArrayList<>();
-
/**
* Convenience method to retrieve a default global ApacheValidatorFactory
*
@@ -94,6 +83,26 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
DEFAULT_FACTORY = aDefaultFactory;
}
+ private static ValueExtractors createBaseValueExtractors(ParticipantFactory participantFactory) {
+ final ValueExtractors result = new ValueExtractors();
+ participantFactory.loadServices(ValueExtractor.class).forEach(result::add);
+ return result;
+ }
+
+ private MessageInterpolator messageResolver;
+ private TraversableResolver traversableResolver;
+ private ConstraintValidatorFactory constraintValidatorFactory;
+ private ParameterNameProvider parameterNameProvider;
+ private ClockProvider clockProvider;
+ private final Map<String, String> properties;
+ private final AnnotationsManager annotationsManager;
+ private final DescriptorManager descriptorManager = new DescriptorManager(this);
+ private final MetadataBuilders metadataBuilders = new MetadataBuilders();
+ private final ConstraintCached constraintsCache = new ConstraintCached();
+ private final Collection<Closeable> toClose = new ArrayList<>();
+ private final ParticipantFactory participantFactory;
+ private final ValueExtractors valueExtractors;
+
/**
* Create a new ApacheValidatorFactory instance.
*/
@@ -105,9 +114,13 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable {
constraintValidatorFactory = configuration.getConstraintValidatorFactory();
clockProvider = configuration.getClockProvider();
- if (ConfigurationImpl.class.isInstance(configuration)) {
- toClose.add(ConfigurationImpl.class.cast(configuration).getClosable());
+ if (configuration instanceof CloseableAble) {
+ toClose.add(((CloseableAble) configuration).getCloseable());
}
+ participantFactory = new ParticipantFactory(ApacheValidatorFactory.class.getClassLoader());
+ toClose.add(participantFactory);
+
+ valueExtractors = createBaseValueExtractors(participantFactory).createChild();
configuration.getValueExtractors().forEach(valueExtractors::add);
annotationsManager = new AnnotationsManager(this);
http://git-wip-us.apache.org/repos/asf/bval/blob/4fd0140f/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 b4d19f6..84b4421 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
@@ -21,14 +21,13 @@ package org.apache.bval.jsr;
import java.io.Closeable;
import java.io.InputStream;
import java.time.Clock;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import javax.validation.BootstrapConfiguration;
@@ -45,11 +44,12 @@ import javax.validation.spi.ConfigurationState;
import javax.validation.spi.ValidationProvider;
import javax.validation.valueextraction.ValueExtractor;
-import org.apache.bval.cdi.BValExtension;
import org.apache.bval.jsr.parameter.DefaultParameterNameProvider;
import org.apache.bval.jsr.resolver.DefaultTraversableResolver;
import org.apache.bval.jsr.util.IOs;
+import org.apache.bval.jsr.valueextraction.ValueExtractors;
import org.apache.bval.jsr.xml.ValidationParser;
+import org.apache.bval.util.CloseableAble;
import org.apache.bval.util.Exceptions;
import org.apache.bval.util.Lazy;
import org.apache.commons.weaver.privilizer.Privileged;
@@ -60,7 +60,7 @@ import org.apache.commons.weaver.privilizer.Privileged;
* hence this can be passed to buildValidatorFactory(ConfigurationState).
* <br/>
*/
-public class ConfigurationImpl implements ApacheValidatorConfiguration, ConfigurationState {
+public class ConfigurationImpl implements ApacheValidatorConfiguration, ConfigurationState, CloseableAble {
private class LazyParticipant<T> extends Lazy<T> {
private boolean locked;
@@ -135,11 +135,13 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
private final LazyParticipant<ClockProvider> clockProvider = new LazyParticipant<>(this::getDefaultClockProvider);
- private Lazy<BootstrapConfiguration> bootstrapConfiguration = new Lazy<>(this::createBootstrapConfiguration);
+ private final ValueExtractors bootstrapValueExtractors = new ValueExtractors();
+ private final ValueExtractors valueExtractors = bootstrapValueExtractors.createChild();
- private Collection<BValExtension.Releasable<?>> releasables = new CopyOnWriteArrayList<>();
+ private final Lazy<BootstrapConfiguration> bootstrapConfiguration = new Lazy<>(this::createBootstrapConfiguration);
- private Set<ValueExtractor<?>> valueExtractors = new HashSet<>();
+ private final Set<InputStream> mappingStreams = new HashSet<>();
+ private final Map<String, String> properties = new HashMap<>();
private boolean beforeCdi = false;
private ClassLoader loader;
@@ -151,10 +153,10 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
private boolean prepared = false;
// END DEFAULTS
- private final Set<InputStream> mappingStreams = new HashSet<>();
- private final Map<String, String> properties = new HashMap<>();
private boolean ignoreXmlConfiguration = false;
+ private ParticipantFactory participantFactory;
+
/**
* Create a new ConfigurationImpl instance.
* @param aState bootstrap state
@@ -369,7 +371,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
@Override
public Set<ValueExtractor<?>> getValueExtractors() {
- return Collections.unmodifiableSet(valueExtractors);
+ return Collections.unmodifiableSet(new LinkedHashSet<>(valueExtractors.getValueExtractors().values()));
}
public void deferBootstrapOverrides() {
@@ -383,13 +385,13 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
}
}
- public Closeable getClosable() {
- return () -> {
- for (final BValExtension.Releasable<?> releasable : releasables) {
- releasable.release();
- }
- releasables.clear();
- };
+ @Override
+ public Closeable getCloseable() {
+ if (participantFactory == null) {
+ return () -> {
+ };
+ }
+ return participantFactory;
}
@Privileged
@@ -407,16 +409,20 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
}
private BootstrapConfiguration createBootstrapConfiguration() {
- if (!ignoreXmlConfiguration) {
- loader = ValidationParser.class.getClassLoader();
- final BootstrapConfiguration xmlBootstrap =
- ValidationParser.processValidationConfig(getProperties().get(Properties.VALIDATION_XML_PATH), this);
- if (xmlBootstrap != null) {
- return xmlBootstrap;
+ try {
+ if (!ignoreXmlConfiguration) {
+ loader = ValidationParser.class.getClassLoader();
+ final BootstrapConfiguration xmlBootstrap =
+ ValidationParser.processValidationConfig(getProperties().get(Properties.VALIDATION_XML_PATH), this);
+ if (xmlBootstrap != null) {
+ return xmlBootstrap;
+ }
}
+ loader = ApacheValidatorFactory.class.getClassLoader();
+ return BootstrapConfigurationImpl.DEFAULT;
+ } finally {
+ participantFactory = new ParticipantFactory(loader);
}
- loader = ApacheValidatorFactory.class.getClassLoader();
- return BootstrapConfigurationImpl.DEFAULT;
}
private void applyBootstrapConfiguration() {
@@ -425,7 +431,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
if (bootstrapConfig.getDefaultProviderClassName() != null) {
this.providerClass = loadClass(bootstrapConfig.getDefaultProviderClassName());
}
-
bootstrapConfig.getProperties().forEach(this::addProperty);
bootstrapConfig.getConstraintMappingResourcePaths().stream().map(ValidationParser::open)
.forEach(this::addMapping);
@@ -442,6 +447,9 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
override(constraintValidatorFactory, bootstrapConfig::getConstraintValidatorFactoryClassName);
override(parameterNameProvider, bootstrapConfig::getParameterNameProviderClassName);
override(clockProvider, bootstrapConfig::getClockProviderClassName);
+
+ bootstrapConfig.getValueExtractorClassNames().stream().<ValueExtractor<?>> map(participantFactory::create)
+ .forEach(bootstrapValueExtractors::add);
}
@SuppressWarnings("unchecked")
@@ -475,25 +483,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur
}
private <T> void override(LazyParticipant<T> participant, Supplier<String> getClassName) {
- final String className = getClassName.get();
- if (className != null) {
- final Class<T> t = loadClass(className);
- participant.override(newInstance(t));
- }
- }
-
- @Privileged
- private <T> T newInstance(final Class<T> cls) {
- try {
- final BValExtension.Releasable<T> releasable = BValExtension.inject(cls);
- releasables.add(releasable);
- return releasable.getInstance();
- } catch (Exception | NoClassDefFoundError e) {
- }
- try {
- return cls.getConstructor().newInstance();
- } catch (final Exception e) {
- throw new ValidationException(e.getMessage(), e);
- }
+ Optional.ofNullable(getClassName.get()).<T> map(participantFactory::create).ifPresent(participant::override);
}
}
http://git-wip-us.apache.org/repos/asf/bval/blob/4fd0140f/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java
new file mode 100644
index 0000000..bde8483
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java
@@ -0,0 +1,107 @@
+/*
+ * 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.jsr;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Collectors;
+
+import javax.validation.ValidationException;
+
+import org.apache.bval.cdi.BValExtension;
+import org.apache.bval.jsr.util.ToUnmodifiable;
+import org.apache.bval.util.Validate;
+import org.apache.commons.weaver.privilizer.Privileged;
+
+/**
+ * Factory object for helper/participant classes. The typical pattern is that this factory loads an instance of a class
+ * by name, taking into account whether Apache BVal is operating in a CDI environment.
+ */
+class ParticipantFactory implements Closeable {
+ private static final String META_INF_SERVICES = "/META_INF/services/";
+
+ private final Collection<BValExtension.Releasable<?>> releasables = new CopyOnWriteArrayList<>();
+ private final ClassLoader loader;
+
+ ParticipantFactory(ClassLoader loader) {
+ super();
+ this.loader = Validate.notNull(loader);
+ }
+
+ @Override
+ public void close() throws IOException {
+ for (final BValExtension.Releasable<?> releasable : releasables) {
+ releasable.release();
+ }
+ releasables.clear();
+ }
+
+ <T> T create(String classname) {
+ return newInstance(loadClass(classname));
+ }
+
+ <T> Set<T> loadServices(Class<T> type) {
+ Validate.notNull(type);
+ try {
+ return Collections.list(loader.getResources(META_INF_SERVICES + type.getName())).stream().map(this::read)
+ .flatMap(Collection::stream).<T> map(this::create).collect(ToUnmodifiable.set());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private Set<String> read(URL url) {
+ try (BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream()))) {
+ return r.lines().map(String::trim).filter(line -> line.charAt(0) != '#').collect(Collectors.toSet());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> Class<T> loadClass(final String className) {
+ try {
+ return (Class<T>) Class.forName(className, true, loader);
+ } catch (final ClassNotFoundException ex) {
+ throw new ValidationException(ex);
+ }
+ }
+
+ @Privileged
+ private <T> T newInstance(final Class<T> cls) {
+ try {
+ final BValExtension.Releasable<T> releasable = BValExtension.inject(cls);
+ releasables.add(releasable);
+ return releasable.getInstance();
+ } catch (Exception | NoClassDefFoundError e) {
+ }
+ try {
+ return cls.getConstructor().newInstance();
+ } catch (final Exception e) {
+ throw new ValidationException(e.getMessage(), e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/bval/blob/4fd0140f/bval-jsr/src/main/java/org/apache/bval/util/CloseableAble.java
----------------------------------------------------------------------
diff --git a/bval-jsr/src/main/java/org/apache/bval/util/CloseableAble.java b/bval-jsr/src/main/java/org/apache/bval/util/CloseableAble.java
new file mode 100644
index 0000000..6fbe316
--- /dev/null
+++ b/bval-jsr/src/main/java/org/apache/bval/util/CloseableAble.java
@@ -0,0 +1,27 @@
+/*
+ * 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.util;
+
+import java.io.Closeable;
+
+@FunctionalInterface
+public interface CloseableAble {
+
+ Closeable getCloseable();
+}