wip
Project: http://git-wip-us.apache.org/repos/asf/bval/repo Commit: http://git-wip-us.apache.org/repos/asf/bval/commit/a43c0b0c Tree: http://git-wip-us.apache.org/repos/asf/bval/tree/a43c0b0c Diff: http://git-wip-us.apache.org/repos/asf/bval/diff/a43c0b0c Branch: refs/heads/bv2 Commit: a43c0b0c7ee43f11a7baa61267db4f00bc20bd4c Parents: 31e1eff Author: Matt Benson <[email protected]> Authored: Wed Nov 15 16:52:45 2017 -0600 Committer: Matt Benson <[email protected]> Committed: Wed Nov 15 16:53:43 2017 -0600 ---------------------------------------------------------------------- .../constraints/FutureOrPresentValidator.java | 138 ++++ .../bval/constraints/FutureValidator.java | 138 ++++ .../bval/constraints/NotBlankValidator.java | 34 + .../bval/constraints/NumberSignValidator.java | 68 ++ .../constraints/PastOrPresentValidator.java | 138 ++++ .../apache/bval/constraints/PastValidator.java | 138 ++++ .../apache/bval/constraints/TimeValidator.java | 44 ++ .../apache/bval/context/ValidationContext.java | 126 ++++ .../bval/jsr/AbstractConstraintDescriptor.java | 32 + .../apache/bval/jsr/ApacheFactoryContext.java | 83 +- .../bval/jsr/ApacheValidatorConfiguration.java | 7 +- .../apache/bval/jsr/ApacheValidatorFactory.java | 161 ++-- .../bval/jsr/BootstrapConfigurationImpl.java | 29 +- .../org/apache/bval/jsr/ConfigurationImpl.java | 128 ++-- .../jsr/ConstraintAnnotationAttributes.java | 38 +- .../org/apache/bval/jsr/ConstraintCached.java | 98 ++- .../org/apache/bval/jsr/ConstraintDefaults.java | 24 +- .../bval/jsr/ConstraintDescriptorImpl.java | 13 + .../apache/bval/jsr/ConstraintValidation.java | 33 +- .../jsr/ConstraintValidatorContextImpl.java | 20 +- .../bval/jsr/ConstraintViolationImpl.java | 69 +- .../java/org/apache/bval/jsr/GraphContext.java | 75 ++ .../jsr/NodeBuilderCustomizableContextImpl.java | 89 +++ .../apache/bval/jsr/NodeContextBuilderImpl.java | 88 +++ .../bval/jsr/ParameterDescriptorImpl.java | 7 + .../apache/bval/jsr/PropertyDescriptorImpl.java | 9 + .../bval/jsr/ReturnValueDescriptorImpl.java | 8 + .../java/org/apache/bval/jsr/ValidatorImpl.java | 141 ++++ .../org/apache/bval/jsr/descriptor/BeanD.java | 112 +++ .../jsr/descriptor/CascadableContainerD.java | 92 +++ .../apache/bval/jsr/descriptor/ComposedD.java | 125 ++++ .../ComputeConstraintValidatorClass.java | 147 ++++ .../apache/bval/jsr/descriptor/ConstraintD.java | 206 +++++ .../bval/jsr/descriptor/ConstructorD.java | 36 + .../jsr/descriptor/ContainerElementTypeD.java | 119 +++ .../bval/jsr/descriptor/CrossParameterD.java | 18 + .../bval/jsr/descriptor/DescriptorManager.java | 68 ++ .../apache/bval/jsr/descriptor/ElementD.java | 103 +++ .../apache/bval/jsr/descriptor/ExecutableD.java | 89 +++ .../org/apache/bval/jsr/descriptor/Finder.java | 100 +++ .../bval/jsr/descriptor/GroupConversion.java | 85 +++ .../bval/jsr/descriptor/MetadataReader.java | 266 +++++++ .../org/apache/bval/jsr/descriptor/MethodD.java | 44 ++ .../apache/bval/jsr/descriptor/ParameterD.java | 62 ++ .../apache/bval/jsr/descriptor/PropertyD.java | 142 ++++ .../bval/jsr/descriptor/ReturnValueD.java | 36 + .../jsr/job/ConstraintValidatorContextImpl.java | 194 +++++ .../org/apache/bval/jsr/job/ValidateBean.java | 58 ++ .../apache/bval/jsr/job/ValidateParameters.java | 165 ++++ .../apache/bval/jsr/job/ValidateProperty.java | 95 +++ .../bval/jsr/job/ValidateReturnValue.java | 104 +++ .../org/apache/bval/jsr/job/ValidationJob.java | 245 ++++++ .../bval/jsr/job/ValidationJobFactory.java | 105 +++ .../bval/jsr/metadata/AnnotationBehavior.java | 34 + .../AnnotationBehaviorMergeStrategy.java | 54 ++ .../bval/jsr/metadata/CompositeBuilder.java | 232 ++++++ .../bval/jsr/metadata/ContainerElementKey.java | 164 ++++ .../apache/bval/jsr/metadata/EmptyBuilder.java | 183 +++++ .../bval/jsr/metadata/HierarchyBuilder.java | 134 ++++ .../bval/jsr/metadata/MetadataBuilder.java | 104 +++ .../bval/jsr/metadata/MetadataBuilders.java | 41 + .../org/apache/bval/jsr/metadata/Metas.java | 245 ++++++ .../bval/jsr/metadata/ParallelBuilder.java | 238 ++++++ .../bval/jsr/metadata/ReflectionBuilder.java | 245 ++++++ .../org/apache/bval/jsr/metadata/Signature.java | 75 ++ .../apache/bval/jsr/metadata/XmlBuilder.java | 715 ++++++++++++++++++ .../bval/jsr/util/AnnotationsManager.java | 279 +++++++ ...ementNodeBuilderCustomizableContextImpl.java | 77 ++ ...nerElementNodeBuilderDefinedContextImpl.java | 65 ++ .../ContainerElementNodeContextBuilderImpl.java | 85 +++ .../org/apache/bval/jsr/util/Exceptions.java | 65 ++ .../java/org/apache/bval/jsr/util/LRUCache.java | 40 + .../LeafNodeBuilderCustomizableContextImpl.java | 23 +- .../java/org/apache/bval/jsr/util/Methods.java | 45 ++ .../NodeBuilderCustomizableContextImpl.java | 55 +- .../jsr/util/NodeBuilderDefinedContextImpl.java | 32 +- .../bval/jsr/util/NodeContextBuilderImpl.java | 52 +- .../java/org/apache/bval/jsr/util/NodeImpl.java | 103 ++- .../java/org/apache/bval/jsr/util/PathImpl.java | 50 +- .../apache/bval/jsr/util/ToUnmodifiable.java | 28 + .../bval/jsr/valueextraction/FxExtractor.java | 96 +++ .../IterableElementExtractor.java | 30 + .../valueextraction/ListElementExtractor.java | 34 + .../bval/jsr/valueextraction/MapExtractor.java | 42 ++ .../jsr/valueextraction/OptionalExtractor.java | 65 ++ .../jsr/valueextraction/ValueExtractors.java | 167 +++++ .../apache/bval/jsr/xml/AnnotationProxy.java | 59 +- .../bval/jsr/xml/AnnotationProxyBuilder.java | 61 +- .../org/apache/bval/jsr/xml/SchemaManager.java | 286 +++++++ .../bval/jsr/xml/ValidationMappingParser.java | 749 ++----------------- .../apache/bval/jsr/xml/ValidationParser.java | 330 ++++---- .../java/org/apache/bval/jsr/xml/XmlUtils.java | 67 ++ .../bval/jsr/DefaultConstraints.properties | 73 +- .../DefaultExtractors.properties | 25 + bval-jsr/src/main/xjb/binding-customization.xjb | 4 +- .../main/xsd/validation-configuration-2.0.xsd | 75 ++ .../src/main/xsd/validation-mapping-2.0.xsd | 297 ++++++++ .../bval/jsr/CustomValidatorFactoryTest.java | 6 + .../test/java/org/apache/bval/jsr/xml/Demo.java | 40 + .../bval/jsr/xml/ValidationParserTest.java | 12 + .../src/test/resources/sample-validation11.xml | 30 + .../src/test/resources/sample-validation2.xml | 30 + 102 files changed, 9526 insertions(+), 1307 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java new file mode 100644 index 0000000..4cc85b1 --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureOrPresentValidator.java @@ -0,0 +1,138 @@ +/* + * 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.constraints; + +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.function.Function; + +import javax.validation.ConstraintValidator; +import javax.validation.constraints.FutureOrPresent; + +/** + * Defines built-in {@link ConstraintValidator} implementations for {@link FutureOrPresent}. + * + * @param <T> + * validated type + */ +public abstract class FutureOrPresentValidator<T extends Comparable<T>> extends TimeValidator<FutureOrPresent, T> { + + public static class ForDate extends FutureOrPresentValidator<Date> { + + public ForDate() { + super(clock -> Date.from(clock.instant())); + } + } + + public static class ForCalendar extends FutureOrPresentValidator<Calendar> { + + public ForCalendar() { + super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone()))); + } + } + + public static class ForInstant extends FutureOrPresentValidator<Instant> { + + public ForInstant() { + super(Instant::now); + } + } + + public static class ForChronoLocalDate extends FutureOrPresentValidator<ChronoLocalDate> { + + public ForChronoLocalDate() { + super(LocalDate::now); + } + } + + public static class ForChronoLocalDateTime extends FutureOrPresentValidator<ChronoLocalDateTime<?>> { + + public ForChronoLocalDateTime() { + super(LocalDateTime::now); + } + } + + public static class ForLocalTime extends FutureOrPresentValidator<LocalTime> { + + public ForLocalTime() { + super(LocalTime::now); + } + } + + public static class ForOffsetDateTime extends FutureOrPresentValidator<OffsetDateTime> { + + public ForOffsetDateTime() { + super(OffsetDateTime::now); + } + } + + public static class ForOffsetTime extends FutureOrPresentValidator<OffsetTime> { + + public ForOffsetTime() { + super(OffsetTime::now); + } + } + + public static class ForChronoZonedDateTime extends FutureOrPresentValidator<ChronoZonedDateTime<?>> { + + public ForChronoZonedDateTime() { + super(ZonedDateTime::now); + } + } + + public static class ForMonthDay extends FutureOrPresentValidator<MonthDay> { + + public ForMonthDay() { + super(MonthDay::now); + } + } + + public static class ForYear extends FutureOrPresentValidator<Year> { + + public ForYear() { + super(Year::now); + } + } + + public static class ForYearMonth extends FutureOrPresentValidator<YearMonth> { + + public ForYearMonth() { + super(YearMonth::now); + } + } + + protected FutureOrPresentValidator(Function<Clock, T> now) { + super(now, n -> n >= 0); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java new file mode 100644 index 0000000..dd6116b --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/constraints/FutureValidator.java @@ -0,0 +1,138 @@ +/* + * 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.constraints; + +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.function.Function; + +import javax.validation.ConstraintValidator; +import javax.validation.constraints.Future; + +/** + * Defines built-in {@link ConstraintValidator} implementations for {@link Future}. + * + * @param <T> + * validated type + */ +public abstract class FutureValidator<T extends Comparable<T>> extends TimeValidator<Future, T> { + + public static class ForDate extends FutureValidator<Date> { + + public ForDate() { + super(clock -> Date.from(clock.instant())); + } + } + + public static class ForCalendar extends FutureValidator<Calendar> { + + public ForCalendar() { + super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone()))); + } + } + + public static class ForInstant extends FutureValidator<Instant> { + + public ForInstant() { + super(Instant::now); + } + } + + public static class ForChronoLocalDate extends FutureValidator<ChronoLocalDate> { + + public ForChronoLocalDate() { + super(LocalDate::now); + } + } + + public static class ForChronoLocalDateTime extends FutureValidator<ChronoLocalDateTime<?>> { + + public ForChronoLocalDateTime() { + super(LocalDateTime::now); + } + } + + public static class ForLocalTime extends FutureValidator<LocalTime> { + + public ForLocalTime() { + super(LocalTime::now); + } + } + + public static class ForOffsetDateTime extends FutureValidator<OffsetDateTime> { + + public ForOffsetDateTime() { + super(OffsetDateTime::now); + } + } + + public static class ForOffsetTime extends FutureValidator<OffsetTime> { + + public ForOffsetTime() { + super(OffsetTime::now); + } + } + + public static class ForChronoZonedDateTime extends FutureValidator<ChronoZonedDateTime<?>> { + + public ForChronoZonedDateTime() { + super(ZonedDateTime::now); + } + } + + public static class ForMonthDay extends FutureValidator<MonthDay> { + + public ForMonthDay() { + super(MonthDay::now); + } + } + + public static class ForYear extends FutureValidator<Year> { + + public ForYear() { + super(Year::now); + } + } + + public static class ForYearMonth extends FutureValidator<YearMonth> { + + public ForYearMonth() { + super(YearMonth::now); + } + } + + protected FutureValidator(Function<Clock, T> now) { + super(now, n -> n > 0); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java new file mode 100644 index 0000000..e201c0d --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NotBlankValidator.java @@ -0,0 +1,34 @@ +/* + * 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.constraints; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraints.NotBlank; + +/** + * Validate {@link NotBlank} for {@link CharSequence}. + */ +public class NotBlankValidator implements ConstraintValidator<NotBlank, CharSequence> { + + @Override + public boolean isValid(CharSequence value, ConstraintValidatorContext context) { + return value == null || value.length() > 0 && !value.chars().allMatch(Character::isWhitespace); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java new file mode 100644 index 0000000..fe8f59c --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/constraints/NumberSignValidator.java @@ -0,0 +1,68 @@ +/* + * 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.constraints; + +import java.util.function.IntPredicate; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraints.Negative; + +import org.apache.bval.util.Validate; + +/** + * Description: validate positive/negative number values. + */ +public abstract class NumberSignValidator implements ConstraintValidator<Negative, Number> { + public static class ForPositive extends NumberSignValidator { + public static class OrZero extends NumberSignValidator { + public OrZero() { + super(n -> n >= 0); + } + } + + public ForPositive() { + super(n -> n > 0); + } + } + + public static class ForNegative extends NumberSignValidator { + public static class OrZero extends NumberSignValidator { + public OrZero() { + super(n -> n <= 0); + } + } + + public ForNegative() { + super(n -> n < 0); + } + } + + private final IntPredicate comparisonTest; + + protected NumberSignValidator(IntPredicate comparisonTest) { + super(); + this.comparisonTest = Validate.notNull(comparisonTest); + } + + @Override + public boolean isValid(Number value, ConstraintValidatorContext context) { + return value == null || comparisonTest.test(Double.compare(value.doubleValue(), 0.0)); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java new file mode 100644 index 0000000..d1e3e19 --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/constraints/PastOrPresentValidator.java @@ -0,0 +1,138 @@ +/* + * 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.constraints; + +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.function.Function; + +import javax.validation.ConstraintValidator; +import javax.validation.constraints.PastOrPresent; + +/** + * Defines built-in {@link ConstraintValidator} implementations for {@link PastOrPresent}. + * + * @param <T> + * validated type + */ +public abstract class PastOrPresentValidator<T extends Comparable<T>> extends TimeValidator<PastOrPresent, T> { + + public static class ForDate extends PastOrPresentValidator<Date> { + + public ForDate() { + super(clock -> Date.from(clock.instant())); + } + } + + public static class ForCalendar extends PastOrPresentValidator<Calendar> { + + public ForCalendar() { + super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone()))); + } + } + + public static class ForInstant extends PastOrPresentValidator<Instant> { + + public ForInstant() { + super(Instant::now); + } + } + + public static class ForChronoLocalDate extends PastOrPresentValidator<ChronoLocalDate> { + + public ForChronoLocalDate() { + super(LocalDate::now); + } + } + + public static class ForChronoLocalDateTime extends PastOrPresentValidator<ChronoLocalDateTime<?>> { + + public ForChronoLocalDateTime() { + super(LocalDateTime::now); + } + } + + public static class ForLocalTime extends PastOrPresentValidator<LocalTime> { + + public ForLocalTime() { + super(LocalTime::now); + } + } + + public static class ForOffsetDateTime extends PastOrPresentValidator<OffsetDateTime> { + + public ForOffsetDateTime() { + super(OffsetDateTime::now); + } + } + + public static class ForOffsetTime extends PastOrPresentValidator<OffsetTime> { + + public ForOffsetTime() { + super(OffsetTime::now); + } + } + + public static class ForChronoZonedDateTime extends PastOrPresentValidator<ChronoZonedDateTime<?>> { + + public ForChronoZonedDateTime() { + super(ZonedDateTime::now); + } + } + + public static class ForMonthDay extends PastOrPresentValidator<MonthDay> { + + public ForMonthDay() { + super(MonthDay::now); + } + } + + public static class ForYear extends PastOrPresentValidator<Year> { + + public ForYear() { + super(Year::now); + } + } + + public static class ForYearMonth extends PastOrPresentValidator<YearMonth> { + + public ForYearMonth() { + super(YearMonth::now); + } + } + + protected PastOrPresentValidator(Function<Clock, T> now) { + super(now, n -> n <= 0); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java new file mode 100644 index 0000000..0136d83 --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/constraints/PastValidator.java @@ -0,0 +1,138 @@ +/* + * 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.constraints; + +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.function.Function; + +import javax.validation.ConstraintValidator; +import javax.validation.constraints.Past; + +/** + * Defines built-in {@link ConstraintValidator} implementations for {@link Past}. + * + * @param <T> + * validated type + */ +public abstract class PastValidator<T extends Comparable<T>> extends TimeValidator<Past, T> { + + public static class ForDate extends PastValidator<Date> { + + public ForDate() { + super(clock -> Date.from(clock.instant())); + } + } + + public static class ForCalendar extends PastValidator<Calendar> { + + public ForCalendar() { + super(clock -> GregorianCalendar.from(clock.instant().atZone(clock.getZone()))); + } + } + + public static class ForInstant extends PastValidator<Instant> { + + public ForInstant() { + super(Instant::now); + } + } + + public static class ForChronoLocalDate extends PastValidator<ChronoLocalDate> { + + public ForChronoLocalDate() { + super(LocalDate::now); + } + } + + public static class ForChronoLocalDateTime extends PastValidator<ChronoLocalDateTime<?>> { + + public ForChronoLocalDateTime() { + super(LocalDateTime::now); + } + } + + public static class ForLocalTime extends PastValidator<LocalTime> { + + public ForLocalTime() { + super(LocalTime::now); + } + } + + public static class ForOffsetDateTime extends PastValidator<OffsetDateTime> { + + public ForOffsetDateTime() { + super(OffsetDateTime::now); + } + } + + public static class ForOffsetTime extends PastValidator<OffsetTime> { + + public ForOffsetTime() { + super(OffsetTime::now); + } + } + + public static class ForChronoZonedDateTime extends PastValidator<ChronoZonedDateTime<?>> { + + public ForChronoZonedDateTime() { + super(ZonedDateTime::now); + } + } + + public static class ForMonthDay extends PastValidator<MonthDay> { + + public ForMonthDay() { + super(MonthDay::now); + } + } + + public static class ForYear extends PastValidator<Year> { + + public ForYear() { + super(Year::now); + } + } + + public static class ForYearMonth extends PastValidator<YearMonth> { + + public ForYearMonth() { + super(YearMonth::now); + } + } + + protected PastValidator(Function<Clock, T> now) { + super(now, n -> n < 0); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java b/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java new file mode 100644 index 0000000..02e3836 --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/constraints/TimeValidator.java @@ -0,0 +1,44 @@ +/* + * 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.constraints; + +import java.lang.annotation.Annotation; +import java.time.Clock; +import java.util.function.Function; +import java.util.function.IntPredicate; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public abstract class TimeValidator<A extends Annotation, T extends Comparable<T>> implements ConstraintValidator<A, T> { + + private final Function<Clock, T> now; + private final IntPredicate test; + + protected TimeValidator(Function<Clock, T> now, IntPredicate test) { + super(); + this.now = now; + this.test = test; + } + + @Override + public final boolean isValid(T value, ConstraintValidatorContext context) { + return value == null || test.test(value.compareTo(now.apply(context.getClockProvider().getClock()))); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java b/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java new file mode 100644 index 0000000..3cdd7bc --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/context/ValidationContext.java @@ -0,0 +1,126 @@ +package org.apache.bval.context; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import javax.validation.ClockProvider; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Path; +import javax.validation.ValidationException; +import javax.validation.metadata.CascadableDescriptor; +import javax.validation.metadata.ContainerDescriptor; +import javax.validation.metadata.ElementDescriptor; + +import org.apache.bval.jsr.ApacheValidatorFactory; +import org.apache.bval.jsr.descriptor.BeanD; +import org.apache.bval.jsr.util.Exceptions; +import org.apache.bval.jsr.util.PathImpl; +import org.apache.bval.model.ValidationListener; +import org.apache.bval.util.Validate; + +/** + * Context for a single validation call over one object or graph. + */ +public class ValidationContext { + + abstract class ElementContext<D> { + + class ValidatorContext implements ConstraintValidatorContext { + private final List<ValidationListener.Error> errorMessages = new LinkedList<>(); + private boolean disableDefaultConstraintViolation; + + /** + * Get the queued error messages. + * + * @return List + */ + List<ValidationListener.Error> getErrorMessages() { + if (disableDefaultConstraintViolation && errorMessages.isEmpty()) { + throw new ValidationException( + "At least one custom message must be created if the default error message gets disabled."); + } + + List<ValidationListener.Error> returnedErrorMessages = new ArrayList<>(errorMessages); + if (!disableDefaultConstraintViolation) { + returnedErrorMessages + .add(new ValidationListener.Error(getDefaultConstraintMessageTemplate(), getPath(), null)); + } + return returnedErrorMessages; + } + + @Override + public void disableDefaultConstraintViolation() { + this.disableDefaultConstraintViolation = true; + } + + @Override + public String getDefaultConstraintMessageTemplate() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ConstraintViolationBuilder buildConstraintViolationWithTemplate(String messageTemplate) { + // TODO Auto-generated method stub + return null; + } + + @Override + public final ClockProvider getClockProvider() { + return validatorFactory.getClockProvider(); + } + + @Override + public final <T> T unwrap(Class<T> type) { + Exceptions.raiseUnless(type.isInstance(this), ValidationException::new, "Type %s not supported", type); + + return type.cast(this); + } + } + + protected final D descriptor; + + ElementContext(D descriptor) { + super(); + this.descriptor = Validate.notNull(descriptor, "descriptor"); + } + + protected abstract PathImpl getPath(); + } + + private class BeanContext extends ElementContext<BeanD> { + BeanContext(BeanD descriptor) { + super(descriptor); + } + + @Override + protected PathImpl getPath() { + return PathImpl.create(); + } + } + + private class CascadableContainerContext<D extends ElementDescriptor & CascadableDescriptor & ContainerDescriptor> + extends ElementContext<D> { + + private final PathImpl path; + + CascadableContainerContext(D descriptor, Path path) { + super(descriptor); + this.path = PathImpl.copy(Validate.notNull(path, "path")); + } + + @Override + protected PathImpl getPath() { + // careful, live + return path; + } + } + + private final ApacheValidatorFactory validatorFactory; + + public ValidationContext(ApacheValidatorFactory validatorFactory) { + super(); + this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory"); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java new file mode 100644 index 0000000..4c303ae --- /dev/null +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/AbstractConstraintDescriptor.java @@ -0,0 +1,32 @@ +package org.apache.bval.jsr; + +import java.lang.annotation.Annotation; +import java.util.Set; + +import javax.validation.Payload; +import javax.validation.metadata.ConstraintDescriptor; +import javax.validation.metadata.ValidateUnwrappedValue; +import javax.validation.valueextraction.Unwrapping; + +abstract class AbstractConstraintDescriptor<T extends Annotation> implements ConstraintDescriptor<T> { + + @Override + public ValidateUnwrappedValue getValueUnwrapping() { + final Set<Class<? extends Payload>> payload = getPayload(); + if (payload != null) { + if (payload.contains(Unwrapping.Unwrap.class)) { + return ValidateUnwrappedValue.UNWRAP; + } + if (payload.contains(Unwrapping.Skip.class)) { + return ValidateUnwrappedValue.SKIP; + } + } + // TODO handle UnwrapByDefault extractors + return ValidateUnwrappedValue.DEFAULT; + } + + @Override + public <U> U unwrap(Class<U> type) { + throw new UnsupportedOperationException(); + } +} http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java index 8f68b9e..b310503 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java @@ -18,46 +18,56 @@ */ package org.apache.bval.jsr; -import org.apache.bval.MetaBeanFinder; -import org.apache.bval.util.reflection.Reflection; -import org.apache.commons.weaver.privilizer.Privilizing; -import org.apache.commons.weaver.privilizer.Privilizing.CallTo; - +import javax.validation.ClockProvider; import javax.validation.ConstraintValidatorFactory; import javax.validation.MessageInterpolator; import javax.validation.ParameterNameProvider; import javax.validation.TraversableResolver; import javax.validation.Validator; import javax.validation.ValidatorContext; +import javax.validation.valueextraction.ValueExtractor; + +import org.apache.bval.MetaBeanFinder; +import org.apache.bval.jsr.descriptor.DescriptorManager; +import org.apache.bval.jsr.groups.GroupsComputer; +import org.apache.bval.jsr.valueextraction.ValueExtractors; +import org.apache.bval.util.Lazy; +import org.apache.bval.util.reflection.Reflection; +import org.apache.commons.weaver.privilizer.Privilizing; +import org.apache.commons.weaver.privilizer.Privilizing.CallTo; /** - * Description: Represents the context that is used to create - * {@link ClassValidator} instances. + * Description: Represents the context that is used to create {@link ClassValidator} instances. */ @Privilizing(@CallTo(Reflection.class)) public class ApacheFactoryContext implements ValidatorContext { + private final Lazy<GroupsComputer> groupsComputer = new Lazy<>(GroupsComputer::new); private final ApacheValidatorFactory factory; + private final ValueExtractors valueExtractors; private volatile MetaBeanFinder metaBeanFinder; private MessageInterpolator messageInterpolator; private TraversableResolver traversableResolver; private ParameterNameProvider parameterNameProvider; private ConstraintValidatorFactory constraintValidatorFactory; + private ClockProvider clockProvider; /** * Create a new ApacheFactoryContext instance. * - * @param factory validator factory - * @param metaBeanFinder meta finder + * @param factory + * validator factory + * @param metaBeanFinder + * meta finder */ public ApacheFactoryContext(ApacheValidatorFactory factory, MetaBeanFinder metaBeanFinder) { this.factory = factory; this.metaBeanFinder = metaBeanFinder; + valueExtractors = factory.getValueExtractors().createChild(); } /** - * Get the {@link ApacheValidatorFactory} used by this - * {@link ApacheFactoryContext}. + * Get the {@link ApacheValidatorFactory} used by this {@link ApacheFactoryContext}. * * @return {@link ApacheValidatorFactory} */ @@ -75,13 +85,13 @@ public class ApacheFactoryContext implements ValidatorContext { } /** - * Discard cached metadata. Calling this method unnecessarily has the effect of severly - * limiting performance, therefore only do so when changes have been made that affect - * validation metadata, i.e. particularly NOT in response to: + * Discard cached metadata. Calling this method unnecessarily has the effect of severly limiting performance, + * therefore only do so when changes have been made that affect validation metadata, i.e. particularly NOT in + * response to: * <ul> - * <li>{@link #messageInterpolator(MessageInterpolator)}</li> - * <li>{@link #traversableResolver(TraversableResolver)}</li> - * <li>{@link #constraintValidatorFactory(ConstraintValidatorFactory)</li> + * <li>{@link #messageInterpolator(MessageInterpolator)}</li> + * <li>{@link #traversableResolver(TraversableResolver)}</li> + * <li>{@link #constraintValidatorFactory(ConstraintValidatorFactory)</li> * </ul> */ private synchronized void resetMeta() { @@ -92,7 +102,7 @@ public class ApacheFactoryContext implements ValidatorContext { * {@inheritDoc} */ @Override - public ValidatorContext messageInterpolator(MessageInterpolator messageInterpolator) { + public ApacheFactoryContext messageInterpolator(MessageInterpolator messageInterpolator) { this.messageInterpolator = messageInterpolator; return this; } @@ -101,7 +111,7 @@ public class ApacheFactoryContext implements ValidatorContext { * {@inheritDoc} */ @Override - public ValidatorContext traversableResolver(TraversableResolver traversableResolver) { + public ApacheFactoryContext traversableResolver(TraversableResolver traversableResolver) { this.traversableResolver = traversableResolver; return this; } @@ -110,18 +120,30 @@ public class ApacheFactoryContext implements ValidatorContext { * {@inheritDoc} */ @Override - public ValidatorContext constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { + public ApacheFactoryContext constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { this.constraintValidatorFactory = constraintValidatorFactory; return this; } @Override - public ValidatorContext parameterNameProvider(ParameterNameProvider parameterNameProvider) { + public ApacheFactoryContext parameterNameProvider(ParameterNameProvider parameterNameProvider) { this.parameterNameProvider = parameterNameProvider; resetMeta(); // needed since parameter names are a component of validation metadata return this; } + @Override + public ApacheFactoryContext clockProvider(ClockProvider clockProvider) { + this.clockProvider = clockProvider; + return this; + } + + @Override + public ApacheFactoryContext addValueExtractor(ValueExtractor<?> extractor) { + valueExtractors.addValueExtractor(extractor); + return this; + } + /** * Get the {@link ConstraintValidatorFactory}. * @@ -137,7 +159,7 @@ public class ApacheFactoryContext implements ValidatorContext { */ @Override public Validator getValidator() { - return new ClassValidator(this); + return new ValidatorImpl(this); } /** @@ -162,6 +184,23 @@ public class ApacheFactoryContext implements ValidatorContext { return parameterNameProvider == null ? factory.getParameterNameProvider() : parameterNameProvider; } + public ClockProvider getClockProvider() { + return clockProvider == null ? factory.getClockProvider() : clockProvider; + } + + public ValueExtractors getValueExtractors() { + return valueExtractors; + } + + public DescriptorManager getDescriptorManager() { + // TODO handle context customizations + return factory.getDescriptorManager(); + } + + public GroupsComputer getGroupsComputer() { + return groupsComputer.get(); + } + boolean isTreatMapsLikeBeans() { return Boolean .parseBoolean(factory.getProperties().get(ApacheValidatorConfiguration.Properties.TREAT_MAPS_LIKE_BEANS)); http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java index fb64d4e..81187f3 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorConfiguration.java @@ -32,7 +32,7 @@ public interface ApacheValidatorConfiguration extends Configuration<ApacheValida /** * Proprietary property keys for {@link ConfigurationImpl} */ - public interface Properties { + interface Properties { /** * the location where to look for the validation.xml file. * default: "META-INF/validation.xml" @@ -91,5 +91,10 @@ public interface ApacheValidatorConfiguration extends Configuration<ApacheValida * </ol> */ String METABEAN_FACTORY_CLASSNAMES = "apache.bval.metabean-factory-classnames"; + + /** + * Size to use for caching of constraint-related information. Default is {@code 50}. + */ + String CONSTRAINTS_CACHE_SIZE = "apache.bval.constraints-cache-size"; } } http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/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 5e6a611..eb760a1 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 @@ -18,11 +18,39 @@ */ package org.apache.bval.jsr; +import java.io.Closeable; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.validation.ClockProvider; +import javax.validation.ConstraintValidatorFactory; +import javax.validation.MessageInterpolator; +import javax.validation.ParameterNameProvider; +import javax.validation.TraversableResolver; +import javax.validation.Validation; +import javax.validation.ValidationException; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import javax.validation.spi.ConfigurationState; + import org.apache.bval.IntrospectorMetaBeanFactory; import org.apache.bval.MetaBeanBuilder; import org.apache.bval.MetaBeanFactory; import org.apache.bval.MetaBeanFinder; import org.apache.bval.MetaBeanManager; +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.AnnotationIgnores; import org.apache.bval.jsr.xml.MetaConstraint; import org.apache.bval.jsr.xml.ValidationMappingParser; @@ -37,28 +65,6 @@ import org.apache.commons.weaver.privilizer.Privileged; import org.apache.commons.weaver.privilizer.Privilizing; import org.apache.commons.weaver.privilizer.Privilizing.CallTo; -import javax.validation.ConstraintValidatorFactory; -import javax.validation.MessageInterpolator; -import javax.validation.ParameterNameProvider; -import javax.validation.TraversableResolver; -import javax.validation.Validation; -import javax.validation.ValidationException; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import javax.validation.spi.ConfigurationState; -import java.io.Closeable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - /** * Description: a factory is a complete configurated object that can create * validators.<br/> @@ -74,7 +80,12 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { 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(); /** * information from xml parsing @@ -89,7 +100,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { private final ConcurrentMap<Class<?>, List<AccessStrategy>> validAccesses; private final ConcurrentMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>> constraintMap; - private final Collection<Closeable> toClose = new ArrayList<Closeable>(); + private final Collection<Closeable> toClose = new ArrayList<>(); private final MetaBeanFinder defaultMetaBeanFinder; /** @@ -112,7 +123,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { * @return a new instance of MetaBeanManager with adequate MetaBeanFactories */ protected MetaBeanFinder buildMetaBeanFinder() { - final List<MetaBeanFactory> builders = new ArrayList<MetaBeanFactory>(); + final List<MetaBeanFactory> builders = new ArrayList<>(); if (Boolean.parseBoolean(getProperties().get(ApacheValidatorConfiguration.Properties.ENABLE_INTROSPECTOR))) { builders.add(new IntrospectorMetaBeanFactory()); } @@ -121,9 +132,8 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { if (factoryClassNames != null) { for (String clsName : factoryClassNames) { // cast, relying on #createMetaBeanFactory to throw the exception if incompatible: - @SuppressWarnings("unchecked") final Class<? extends MetaBeanFactory> factoryClass = - (Class<? extends MetaBeanFactory>) loadClass(clsName); + loadClass(clsName).asSubclass(MetaBeanFactory.class); builders.add(createMetaBeanFactory(factoryClass)); } } @@ -173,24 +183,27 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { * Create a new ApacheValidatorFactory instance. */ public ApacheValidatorFactory(ConfigurationState configuration) { - properties = new HashMap<String, String>(configuration.getProperties()); - defaultSequences = new HashMap<Class<?>, Class<?>[]>(); - validAccesses = new ConcurrentHashMap<Class<?>, List<AccessStrategy>>(); - constraintMap = new ConcurrentHashMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>>(); + properties = new HashMap<>(configuration.getProperties()); + defaultSequences = new HashMap<>(); + validAccesses = new ConcurrentHashMap<>(); + constraintMap = new ConcurrentHashMap<>(); parameterNameProvider = configuration.getParameterNameProvider(); messageResolver = configuration.getMessageInterpolator(); traversableResolver = configuration.getTraversableResolver(); constraintValidatorFactory = configuration.getConstraintValidatorFactory(); + clockProvider = configuration.getClockProvider(); if (ConfigurationImpl.class.isInstance(configuration)) { - final ConfigurationImpl impl = ConfigurationImpl.class.cast(configuration); - toClose.add(impl.getClosable()); + toClose.add(ConfigurationImpl.class.cast(configuration).getClosable()); } new ValidationMappingParser(this).processMappingConfig(configuration.getMappingStreams()); defaultMetaBeanFinder = buildMetaBeanFinder(); + + configuration.getValueExtractors().forEach(valueExtractors::addValueExtractor); + annotationsManager = new AnnotationsManager(this); } /** @@ -203,8 +216,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Shortcut method to create a new Validator instance with factory's - * settings + * Shortcut method to create a new Validator instance with factory's settings * * @return the new validator instance */ @@ -271,6 +283,12 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } } + public void setClockProvider(final ClockProvider clockProvider) { + if (clockProvider != null) { + this.clockProvider = clockProvider; + } + } + /** * {@inheritDoc} */ @@ -307,6 +325,11 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } @Override + public ClockProvider getClockProvider() { + return clockProvider; + } + + @Override public void close() { try { for (final Closeable c : toClose) { @@ -319,13 +342,14 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Return an object of the specified type to allow access to the - * provider-specific API. If the Bean Validation provider implementation - * does not support the specified class, the ValidationException is thrown. + * Return an object of the specified type to allow access to the provider-specific API. If the Bean Validation + * provider implementation does not support the specified class, the ValidationException is thrown. * - * @param type the class of the object to be returned. + * @param type + * the class of the object to be returned. * @return an instance of the specified class - * @throws ValidationException if the provider does not support the call. + * @throws ValidationException + * if the provider does not support the call. */ @Override public <T> T unwrap(final Class<T> type) { @@ -392,8 +416,34 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Add a meta-constraint to this {@link ApacheValidatorFactory}'s runtime - * customizations. + * Get the {@link AnnotationsManager}. + * + * @return {@link AnnotationsManager} + */ + public AnnotationsManager getAnnotationsManager() { + return annotationsManager; + } + + /** + * Get the {@link DescriptorManager}. + * + * @return {@link DescriptorManager} + */ + public DescriptorManager getDescriptorManager() { + return descriptorManager; + } + + /** + * Get the {@link ValueExtractors}. + * + * @return {@link ValueExtractors} + */ + public ValueExtractors getValueExtractors() { + return valueExtractors; + } + + /** + * Add a meta-constraint to this {@link ApacheValidatorFactory}'s runtime customizations. * * @param beanClass * @param metaConstraint @@ -401,7 +451,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { public void addMetaConstraint(final Class<?> beanClass, final MetaConstraint<?, ?> metaConstraint) { List<MetaConstraint<?, ? extends Annotation>> slot = constraintMap.get(beanClass); if (slot == null) { - slot = new ArrayList<MetaConstraint<?, ? extends Annotation>>(); + slot = new ArrayList<>(); final List<MetaConstraint<?, ? extends Annotation>> old = constraintMap.putIfAbsent(beanClass, slot); if (old != null) { slot = old; @@ -420,7 +470,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { public void addValid(Class<?> beanClass, AccessStrategy accessStrategy) { List<AccessStrategy> slot = validAccesses.get(beanClass); if (slot == null) { - slot = new ArrayList<AccessStrategy>(); + slot = new ArrayList<>(); final List<AccessStrategy> old = validAccesses.putIfAbsent(beanClass, slot); if (old != null) { slot = old; @@ -444,8 +494,7 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { * * @param <T> * @param beanClass - * @return List of {@link MetaConstraint}s applicable to - * <code>beanClass</code> + * @return List of {@link MetaConstraint}s applicable to <code>beanClass</code> */ public <T> List<MetaConstraint<T, ? extends Annotation>> getMetaConstraints(Class<T> beanClass) { final List<MetaConstraint<?, ? extends Annotation>> slot = constraintMap.get(beanClass); @@ -459,16 +508,15 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Get the {@link AccessStrategy} {@link List} indicating nested bean - * validations that must be triggered in the course of validating a - * <code>beanClass</code> graph. + * Get the {@link AccessStrategy} {@link List} indicating nested bean validations that must be triggered in the + * course of validating a <code>beanClass</code> graph. * * @param beanClass * @return {@link List} of {@link AccessStrategy} */ public List<AccessStrategy> getValidAccesses(Class<?> beanClass) { final List<AccessStrategy> slot = validAccesses.get(beanClass); - return slot == null ? Collections.<AccessStrategy> emptyList() : Collections.unmodifiableList(slot); + return slot == null ? Collections.emptyList() : Collections.unmodifiableList(slot); } /** @@ -481,6 +529,10 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { return safeArray(defaultSequences.get(beanClass)); } + public MetadataBuilders getMetadataBuilders() { + return metadataBuilders; + } + private static Class<?>[] safeArray(Class<?>... array) { return array == null || array.length == 0 ? ObjectUtils.EMPTY_CLASS_ARRAY : array.clone(); } @@ -519,9 +571,8 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * separate class to prevent the classloader to immediately load optional - * classes: XMLMetaBeanManager, XMLMetaBeanFactory, XMLMetaBeanBuilder that - * might not be available in the classpath + * separate class to prevent the classloader to immediately load optional classes: XMLMetaBeanManager, + * XMLMetaBeanFactory, XMLMetaBeanBuilder that might not be available in the classpath */ private static class XMLMetaBeanManagerCreator { @@ -530,10 +581,10 @@ public class ApacheValidatorFactory implements ValidatorFactory, Cloneable { } /** - * Create the {@link MetaBeanManager} to process JSR303 XML. Requires - * bval-xstream at RT. + * Create the {@link MetaBeanManager} to process JSR303 XML. Requires bval-xstream at RT. * - * @param builders meta bean builders + * @param builders + * meta bean builders * @return {@link MetaBeanManager} */ // NOTE - We return MetaBeanManager instead of XMLMetaBeanManager to http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java index 3a3abf1..d85ab51 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/BootstrapConfigurationImpl.java @@ -34,12 +34,15 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { private String messageInterpolatorClassName; private String constraintValidatorFactoryClassName; private String defaultProviderClassName; + private String clockProviderClassName; + private Set<String> valueExtractorClassNames; public BootstrapConfigurationImpl(final String defaultProviderClassName, final String constraintValidatorFactoryClassName, final String messageInterpolatorClassName, final String traversableResolverClassName, final String parameterNameProviderClassName, final Set<String> constraintMappingResourcePaths, final boolean executableValidationEnabled, - final Set<ExecutableType> defaultValidatedExecutableTypes, final Map<String, String> properties) { + final Set<ExecutableType> defaultValidatedExecutableTypes, final Map<String, String> properties, + final String clockProviderClassName, final Set<String> valueExtractorClassNames) { this.properties = Collections.unmodifiableMap(properties); this.defaultValidatedExecutableTypes = Collections.unmodifiableSet(defaultValidatedExecutableTypes); this.executableValidationEnabled = executableValidationEnabled; @@ -49,6 +52,8 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { this.messageInterpolatorClassName = messageInterpolatorClassName; this.constraintValidatorFactoryClassName = constraintValidatorFactoryClassName; this.defaultProviderClassName = defaultProviderClassName; + this.clockProviderClassName = clockProviderClassName; + this.valueExtractorClassNames = valueExtractorClassNames; } @Override @@ -78,7 +83,7 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { @Override public Set<String> getConstraintMappingResourcePaths() { - return constraintMappingResourcePaths; + return Collections.unmodifiableSet(constraintMappingResourcePaths); } @Override @@ -88,11 +93,27 @@ public class BootstrapConfigurationImpl implements BootstrapConfiguration { @Override public Set<ExecutableType> getDefaultValidatedExecutableTypes() { - return defaultValidatedExecutableTypes; + return Collections.unmodifiableSet(defaultValidatedExecutableTypes); } @Override public Map<String, String> getProperties() { - return properties; + return Collections.unmodifiableMap(properties); + } + + /** + * @since 2.0 + */ + @Override + public String getClockProviderClassName() { + return clockProviderClassName; + } + + /** + * @since 2.0 + */ + @Override + public Set<String> getValueExtractorClassNames() { + return Collections.unmodifiableSet(valueExtractorClassNames); } } http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/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 7c4780f..046d6d2 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 @@ -19,9 +19,10 @@ package org.apache.bval.jsr; import java.io.Closeable; -import java.io.IOException; 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.Map; @@ -29,6 +30,7 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import javax.validation.BootstrapConfiguration; +import javax.validation.ClockProvider; import javax.validation.ConstraintValidatorFactory; import javax.validation.MessageInterpolator; import javax.validation.ParameterNameProvider; @@ -40,6 +42,7 @@ import javax.validation.executable.ExecutableType; import javax.validation.spi.BootstrapState; 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; @@ -76,29 +79,33 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ protected MessageInterpolator defaultMessageInterpolator = new DefaultMessageInterpolator(); protected volatile MessageInterpolator messageInterpolator = defaultMessageInterpolator; - protected Class<? extends MessageInterpolator> messageInterpolatorClass = null; + protected Class<? extends MessageInterpolator> messageInterpolatorClass; /** * Configured {@link ConstraintValidatorFactory} */ protected ConstraintValidatorFactory defaultConstraintValidatorFactory = new DefaultConstraintValidatorFactory(); protected volatile ConstraintValidatorFactory constraintValidatorFactory = defaultConstraintValidatorFactory; - protected Class<? extends ConstraintValidatorFactory> constraintValidatorFactoryClass = null; + protected Class<? extends ConstraintValidatorFactory> constraintValidatorFactoryClass; protected TraversableResolver defaultTraversableResolver = new DefaultTraversableResolver(); protected volatile TraversableResolver traversableResolver = defaultTraversableResolver; - protected Class<? extends TraversableResolver> traversableResolverClass = null; + protected Class<? extends TraversableResolver> traversableResolverClass; protected ParameterNameProvider defaultParameterNameProvider = new DefaultParameterNameProvider(); protected volatile ParameterNameProvider parameterNameProvider = defaultParameterNameProvider; - protected Class<? extends ParameterNameProvider> parameterNameProviderClass = null; + protected Class<? extends ParameterNameProvider> parameterNameProviderClass; protected BootstrapConfiguration bootstrapConfiguration; protected Collection<ExecutableType> executableValidation; - private Collection<BValExtension.Releasable<?>> releasables = - new CopyOnWriteArrayList<BValExtension.Releasable<?>>(); + private Collection<BValExtension.Releasable<?>> releasables = new CopyOnWriteArrayList<>(); + protected ClockProvider defaultClockProvider = Clock::systemDefaultZone; + protected volatile ClockProvider clockProvider = defaultClockProvider; + protected Class<? extends ClockProvider> clockProviderClass; + + protected Set<ValueExtractor<?>> valueExtractors = new HashSet<>(); private boolean beforeCdi = false; @@ -109,8 +116,8 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur private boolean prepared = false; // END DEFAULTS - private Set<InputStream> mappingStreams = new HashSet<InputStream>(); - private Map<String, String> properties = new HashMap<String, String>(); + private Set<InputStream> mappingStreams = new HashSet<>(); + private Map<String, String> properties = new HashMap<>(); private boolean ignoreXmlConfiguration = false; private volatile ValidationParser parser; @@ -134,6 +141,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur } else { throw new ValidationException("either provider or state are required"); } + initializePropertyDefaults(); } /** @@ -141,13 +149,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ApacheValidatorConfiguration traversableResolver(TraversableResolver resolver) { - if (resolver == null) { - return this; + if (resolver != null) { + this.traversableResolverClass = null; + this.traversableResolver = resolver; + this.prepared = false; } - - this.traversableResolverClass = null; - this.traversableResolver = resolver; - this.prepared = false; return this; } @@ -169,13 +175,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ConfigurationImpl messageInterpolator(MessageInterpolator resolver) { - if (resolver == null) { - return this; + if (resolver != null) { + this.messageInterpolatorClass = null; + this.messageInterpolator = resolver; + this.prepared = false; } - - this.messageInterpolatorClass = null; - this.messageInterpolator = resolver; - this.prepared = false; return this; } @@ -184,23 +188,20 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ConfigurationImpl constraintValidatorFactory(ConstraintValidatorFactory constraintFactory) { - if (constraintFactory == null) { - return this; + if (constraintFactory != null) { + this.constraintValidatorFactoryClass = null; + this.constraintValidatorFactory = constraintFactory; + this.prepared = false; } - - this.constraintValidatorFactoryClass = null; - this.constraintValidatorFactory = constraintFactory; - this.prepared = false; return this; } @Override public ApacheValidatorConfiguration parameterNameProvider(ParameterNameProvider parameterNameProvider) { - if (parameterNameProvider == null) { - return this; + if (parameterNameProvider != null) { + this.parameterNameProviderClass = null; + this.parameterNameProvider = parameterNameProvider; } - this.parameterNameProviderClass = null; - this.parameterNameProvider = parameterNameProvider; return this; } @@ -213,10 +214,9 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur */ @Override public ApacheValidatorConfiguration addMapping(InputStream stream) { - if (stream == null) { - return this; + if (stream != null) { + mappingStreams.add(IOs.convertToMarkableInputStream(stream)); } - mappingStreams.add(IOs.convertToMarkableInputStream(stream)); return this; } @@ -297,7 +297,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return defaultMessageInterpolator; } - if (messageInterpolator == defaultMessageInterpolator && messageInterpolatorClass != null) { synchronized (this) { if (messageInterpolator == defaultMessageInterpolator && messageInterpolatorClass != null) { @@ -336,7 +335,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (prepared) { return this; } - createBootstrapConfiguration(); parser.applyConfigWithInstantiation(this); // instantiate the config if needed @@ -367,7 +365,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return constraintValidatorFactory; } - if (constraintValidatorFactory == defaultConstraintValidatorFactory && constraintValidatorFactoryClass != null) { synchronized (this) { @@ -388,7 +385,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return defaultTraversableResolver; } - if (traversableResolver == defaultTraversableResolver && traversableResolverClass != null) { synchronized (this) { if (traversableResolver == defaultTraversableResolver && traversableResolverClass != null) { @@ -404,7 +400,6 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur if (beforeCdi) { return defaultParameterNameProvider; } - if (parameterNameProvider == defaultParameterNameProvider && parameterNameProviderClass != null) { synchronized (this) { if (parameterNameProvider == defaultParameterNameProvider && parameterNameProviderClass != null) { @@ -452,14 +447,11 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur } public Closeable getClosable() { - return new Closeable() { - @Override - public void close() throws IOException { - for (final BValExtension.Releasable<?> releasable : releasables) { - releasable.release(); - } - releasables.clear(); + return () -> { + for (final BValExtension.Releasable<?> releasable : releasables) { + releasable.release(); } + releasables.clear(); }; } @@ -469,8 +461,7 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur final BValExtension.Releasable<T> releasable = BValExtension.inject(cls); releasables.add(releasable); return releasable.getInstance(); - } catch (final Exception e) { - } catch (final NoClassDefFoundError error) { + } catch (Exception | NoClassDefFoundError e) { } try { return cls.newInstance(); @@ -494,4 +485,45 @@ public class ConfigurationImpl implements ApacheValidatorConfiguration, Configur public void parameterNameProviderClass(final Class<? extends ParameterNameProvider> clazz) { parameterNameProviderClass = clazz; } + + @Override + public ApacheValidatorConfiguration clockProvider(ClockProvider clockProvider) { + this.clockProvider = clockProvider; + return this; + } + + @Override + public ApacheValidatorConfiguration addValueExtractor(ValueExtractor<?> extractor) { + valueExtractors.add(extractor); + return this; + } + + @Override + public ClockProvider getDefaultClockProvider() { + return defaultClockProvider; + } + + @Override + public Set<ValueExtractor<?>> getValueExtractors() { + return Collections.unmodifiableSet(valueExtractors); + } + + @Override + public ClockProvider getClockProvider() { + if (beforeCdi) { + return defaultClockProvider; + } + if (clockProvider == defaultClockProvider && clockProviderClass != null) { + synchronized (this) { + if (clockProvider == defaultClockProvider && clockProviderClass != null) { + clockProvider = newInstance(clockProviderClass); + } + } + } + return clockProvider; + } + + protected void initializePropertyDefaults() { + properties.put(Properties.CONSTRAINTS_CACHE_SIZE, Integer.toString(50)); + } } http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java index 24b38ea..6b9842c 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintAnnotationAttributes.java @@ -134,20 +134,16 @@ public enum ConstraintAnnotationAttributes { public <C extends Annotation> Worker<C> analyze(final Class<C> clazz) { if (clazz.getName().startsWith("javax.validation.constraint.")) { // cache only APIs classes to avoid memory leaks @SuppressWarnings("unchecked") - Worker<C> w = Worker.class.cast(WORKER_CACHE.get(clazz)); - if (w == null) { - w = new Worker<C>(clazz); - WORKER_CACHE.putIfAbsent(clazz, w); - return w; - } + final Worker<C> w = (Worker<C>) WORKER_CACHE.computeIfAbsent(clazz, Worker::new); + return w; } return new Worker<C>(clazz); } // this is static but related to Worker - private static final ConcurrentMap<Class<?>, Worker<?>> WORKER_CACHE = new ConcurrentHashMap<Class<?>, Worker<?>>(); + private static final ConcurrentMap<Class<?>, Worker<?>> WORKER_CACHE = new ConcurrentHashMap<>(); private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Method>> METHOD_BY_NAME_AND_CLASS = - new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Method>>(); + new ConcurrentHashMap<>(); private static final Method NULL_METHOD; static { try { @@ -171,14 +167,8 @@ public enum ConstraintAnnotationAttributes { } private Method findMethod(final Class<C> constraintType, final String attributeName) { - ConcurrentMap<String, Method> cache = METHOD_BY_NAME_AND_CLASS.get(constraintType); - if (cache == null) { - cache = new ConcurrentHashMap<String, Method>(); - final ConcurrentMap<String, Method> old = METHOD_BY_NAME_AND_CLASS.putIfAbsent(constraintType, cache); - if (old != null) { - cache = old; - } - } + ConcurrentMap<String, Method> cache = + METHOD_BY_NAME_AND_CLASS.computeIfAbsent(constraintType, t -> new ConcurrentHashMap<>()); final Method found = cache.get(attributeName); if (found != null) { @@ -189,15 +179,19 @@ public enum ConstraintAnnotationAttributes { cache.putIfAbsent(attributeName, NULL_METHOD); return null; } - final Method oldMtd = cache.putIfAbsent(attributeName, m); - if (oldMtd != null) { - return oldMtd; - } - return m; + return cache.computeIfAbsent(attributeName, s -> m); } public boolean isValid() { - return method != null && method != NULL_METHOD; + return method != null && method != NULL_METHOD && TypeUtils.isAssignable(method.getReturnType(), type); + } + + /** + * @since 2.0 + * @return {@link Type} + */ + public Type getSpecificType() { + return isValid() ? method.getGenericReturnType() : type; } public <T> T read(final Annotation constraint) { http://git-wip-us.apache.org/repos/asf/bval/blob/a43c0b0c/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java ---------------------------------------------------------------------- diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java index 1bb012f..5ec3ab7 100644 --- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java +++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintCached.java @@ -18,18 +18,76 @@ */ package org.apache.bval.jsr; -import javax.validation.ConstraintValidator; import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +import javax.validation.ConstraintValidator; +import javax.validation.constraintvalidation.SupportedValidationTarget; +import javax.validation.constraintvalidation.ValidationTarget; + +import org.apache.bval.jsr.util.ToUnmodifiable; +import org.apache.bval.util.ObjectUtils; +import org.apache.bval.util.Validate; /** * Description: hold the relationship annotation->validatedBy[] ConstraintValidator classes that are already parsed in a * cache.<br/> */ public class ConstraintCached { - private final Map<Class<? extends Annotation>, Class<? extends ConstraintValidator<?, ?>>[]> classes = - new HashMap<Class<? extends Annotation>, Class<? extends ConstraintValidator<?, ?>>[]>(); + + /** + * Describes a {@link ConstraintValidator} implementation type. + * + * @since 2.0 + */ + public static final class ConstraintValidatorInfo<T extends Annotation> { + private static final Set<ValidationTarget> DEFAULT_VALIDATION_TARGETS = + Collections.singleton(ValidationTarget.ANNOTATED_ELEMENT); + + private final Class<? extends ConstraintValidator<T, ?>> type; + private Set<ValidationTarget> supportedTargets; + + ConstraintValidatorInfo(Class<? extends ConstraintValidator<T, ?>> type) { + super(); + this.type = Validate.notNull(type); + final SupportedValidationTarget svt = type.getAnnotation(SupportedValidationTarget.class); + + supportedTargets = svt == null ? DEFAULT_VALIDATION_TARGETS + : Collections.unmodifiableSet(EnumSet.copyOf(Arrays.asList(svt.value()))); + } + + public Class<? extends ConstraintValidator<T, ?>> getType() { + return type; + } + + public Set<ValidationTarget> getSupportedTargets() { + return supportedTargets; + } + + @Override + public boolean equals(Object obj) { + return obj == this + || obj instanceof ConstraintValidatorInfo<?> && ((ConstraintValidatorInfo<?>) obj).type.equals(type); + } + + @Override + public int hashCode() { + return Objects.hash(type); + } + } + + private final Map<Class<? extends Annotation>, Set<ConstraintValidatorInfo<?>>> constraintValidatorInfo = + new HashMap<>(); /** * Record the set of validator classes for a given constraint annotation. @@ -39,7 +97,12 @@ public class ConstraintCached { */ public <A extends Annotation> void putConstraintValidator(Class<A> annotationClass, Class<? extends ConstraintValidator<A, ?>>[] definitionClasses) { - classes.put(annotationClass, definitionClasses); + if (ObjectUtils.isEmpty(definitionClasses)) { + return; + } + Validate.notNull(annotationClass, "annotationClass"); + Stream.of(definitionClasses).map(t -> new ConstraintValidatorInfo<>(t)) + .forEach(constraintValidatorInfo.computeIfAbsent(annotationClass, k -> new HashSet<>())::add); } /** @@ -50,20 +113,39 @@ public class ConstraintCached { * @return boolean */ public boolean containsConstraintValidator(Class<? extends Annotation> annotationClass) { - return classes.containsKey(annotationClass); + return constraintValidatorInfo.containsKey(annotationClass); } /** * Get the cached validator classes for the requested constraint annotation. * - * @param annotationClass + * @param constraintType * to look up * @return array of {@link ConstraintValidator} implementation types */ @SuppressWarnings("unchecked") + @Deprecated public <A extends Annotation> Class<? extends ConstraintValidator<A, ?>>[] getConstraintValidators( - Class<A> annotationClass) { - return (Class<? extends ConstraintValidator<A, ?>>[]) classes.get(annotationClass); + Class<A> constraintType) { + final Set<ConstraintValidatorInfo<A>> infos = infos(constraintType); + return infos == null ? new Class[0] + : infos.stream().map(ConstraintValidatorInfo::getType).toArray(Class[]::new); } + public <A extends Annotation> List<Class<? extends ConstraintValidator<A, ?>>> getConstraintValidatorClasses( + Class<A> constraintType) { + final Set<ConstraintValidatorInfo<A>> infos = infos(constraintType); + return infos == null ? Collections.emptyList() + : infos.stream().map(ConstraintValidatorInfo::getType).collect(ToUnmodifiable.list()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private <A extends Annotation> Set<ConstraintValidatorInfo<A>> infos(Class<A> constraintType) { + return (Set) constraintValidatorInfo.get(constraintType); + } + + public <A extends Annotation> Optional<Set<ConstraintValidatorInfo<A>>> getConstraintValidatorInfo( + Class<A> constraintType) { + return Optional.ofNullable(infos(constraintType)).map(Collections::unmodifiableSet); + } }
