Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/ValidatorImpl.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,141 @@ +/* + * 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.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.ValidationException; +import javax.validation.executable.ExecutableValidator; +import javax.validation.metadata.BeanDescriptor; + +import org.apache.bval.jsr.job.ValidationJobFactory; +import org.apache.bval.util.Validate; +import org.apache.bval.util.reflection.Reflection; + +public class ValidatorImpl implements CascadingPropertyValidator, ExecutableValidator { + + private final ApacheFactoryContext validatorContext; + private final ValidationJobFactory validationJobFactory; + + ValidatorImpl(ApacheFactoryContext validatorContext) { + super(); + this.validatorContext = Validate.notNull(validatorContext, "validatorContext"); + this.validationJobFactory = new ValidationJobFactory(validatorContext); + } + + @Override + public BeanDescriptor getConstraintsForClass(Class<?> clazz) { + return validatorContext.getDescriptorManager().getBeanDescriptor(clazz); + } + + @Override + public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) { + return validationJobFactory.validateBean(object, groups).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, boolean cascade, + Class<?>... groups) { + return validationJobFactory.validateProperty(object, propertyName, groups).cascade(cascade).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, + boolean cascade, Class<?>... groups) { + return validationJobFactory.validateValue(beanType, propertyName, value, groups).cascade(cascade).getResults(); + } + + @Override + public ExecutableValidator forExecutables() { + return this; + } + + @Override + public <T> Set<ConstraintViolation<T>> validateParameters(T object, Method method, Object[] parameterValues, + Class<?>... groups) { + return validationJobFactory.validateParameters(object, method, parameterValues, groups).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateReturnValue(T object, Method method, Object returnValue, + Class<?>... groups) { + return validationJobFactory.validateReturnValue(object, method, returnValue, groups).getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateConstructorParameters(Constructor<? extends T> constructor, + Object[] parameterValues, Class<?>... groups) { + return validationJobFactory.<T> validateConstructorParameters(constructor, parameterValues, groups) + .getResults(); + } + + @Override + public <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(Constructor<? extends T> constructor, + T createdObject, Class<?>... groups) { + return validationJobFactory.<T> validateConstructorReturnValue(constructor, createdObject, groups).getResults(); + } + + @Override + public <T> T unwrap(Class<T> type) { + // FIXME 2011-03-27 jw: + // This code is unsecure. + // It should allow only a fixed set of classes. + // Can't fix this because don't know which classes this method should support. + + if (type.isAssignableFrom(getClass())) { + @SuppressWarnings("unchecked") + final T result = (T) this; + return result; + } + if (!(type.isInterface() || Modifier.isAbstract(type.getModifiers()))) { + return newInstance(type); + } + try { + final Class<?> cls = Reflection.toClass(type.getName() + "Impl"); + if (type.isAssignableFrom(cls)) { + @SuppressWarnings("unchecked") + final Class<? extends T> implClass = (Class<? extends T>) cls; + return newInstance(implClass); + } + } catch (ClassNotFoundException e) { + } + throw new ValidationException("Type " + type + " not supported"); + } + + private <T> T newInstance(final Class<T> cls) { + final Constructor<T> cons = Reflection.getDeclaredConstructor(cls, ApacheFactoryContext.class); + if (cons == null) { + throw new ValidationException("Cannot instantiate " + cls); + } + final boolean mustUnset = Reflection.setAccessible(cons, true); + try { + return cons.newInstance(validatorContext); + } catch (final Exception ex) { + throw new ValidationException("Cannot instantiate " + cls, ex); + } finally { + if (mustUnset) { + Reflection.setAccessible(cons, false); + } + } + } +}
Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/BeanD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,122 @@ +/* + * 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.descriptor; + +import java.lang.reflect.Type; +import java.util.EnumSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.validation.metadata.BeanDescriptor; +import javax.validation.metadata.ConstructorDescriptor; +import javax.validation.metadata.MethodDescriptor; +import javax.validation.metadata.MethodType; +import javax.validation.metadata.PropertyDescriptor; + +import org.apache.bval.jsr.groups.GroupStrategy; +import org.apache.bval.jsr.metadata.Signature; +import org.apache.bval.jsr.util.ToUnmodifiable; +import org.apache.bval.util.Exceptions; +import org.apache.bval.util.StringUtils; + +public class BeanD<T> extends ElementD<Class<T>, MetadataReader.ForBean<T>> implements BeanDescriptor { + + private final Class<T> beanClass; + private final Map<String, PropertyDescriptor> propertiesMap; + private final Set<PropertyDescriptor> properties; + private final Map<Signature, ConstructorD<T>> constructors; + private final Map<Signature, MethodD> methods; + private final GroupStrategy groupStrategy; + + BeanD(MetadataReader.ForBean<T> reader) { + super(reader); + this.beanClass = reader.meta.getHost(); + + groupStrategy = reader.getGroupStrategy(); + propertiesMap = reader.getProperties(this); + properties = propertiesMap.values().stream().filter(DescriptorManager::isConstrained).collect(ToUnmodifiable.set()); + constructors = reader.getConstructors(this); + methods = reader.getMethods(this); + } + + @Override + public Class<?> getElementClass() { + return beanClass; + } + + @Override + public boolean isBeanConstrained() { + return hasConstraints() || properties.stream().anyMatch(DescriptorManager::isConstrained); + } + + @Override + public PropertyDescriptor getConstraintsForProperty(String propertyName) { + return Optional.ofNullable(getProperty(propertyName)).filter(DescriptorManager::isConstrained).orElse(null); + } + + @Override + public Set<PropertyDescriptor> getConstrainedProperties() { + return properties; + } + + @Override + public MethodDescriptor getConstraintsForMethod(String methodName, Class<?>... parameterTypes) { + Exceptions.raiseIf(StringUtils.isBlank(methodName), IllegalArgumentException::new, + "method name cannot be null/empty/blank"); + return methods.get(new Signature(methodName, parameterTypes)); + } + + @Override + public Set<MethodDescriptor> getConstrainedMethods(MethodType methodType, MethodType... methodTypes) { + final EnumSet<MethodType> filter = EnumSet.of(methodType, methodTypes); + return methods.values().stream().filter(m -> filter.contains(m.getMethodType())).collect(ToUnmodifiable.set()); + } + + @Override + public ConstructorDescriptor getConstraintsForConstructor(Class<?>... parameterTypes) { + return constructors.get(new Signature(beanClass.getName(), parameterTypes)); + } + + @Override + public Set<ConstructorDescriptor> getConstrainedConstructors() { + return constructors.values().stream().collect(ToUnmodifiable.set()); + } + + public PropertyDescriptor getProperty(String propertyName) { + Exceptions.raiseIf(StringUtils.isBlank(propertyName), IllegalArgumentException::new, + "propertyName was null/empty/blank"); + + return propertiesMap.get(propertyName); + } + + @Override + protected BeanD<T> getBean() { + return this; + } + + @Override + public GroupStrategy getGroupStrategy() { + return groupStrategy; + } + + public final Type getGenericType() { + return getElementClass(); + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CascadableContainerD.java Fri Oct 12 15:00:48 2018 @@ -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.jsr.descriptor; + +import java.lang.reflect.AnnotatedElement; +import java.util.Set; + +import javax.validation.metadata.CascadableDescriptor; +import javax.validation.metadata.ContainerDescriptor; +import javax.validation.metadata.ContainerElementTypeDescriptor; +import javax.validation.metadata.GroupConversionDescriptor; + +import org.apache.bval.jsr.groups.GroupConversion; +import org.apache.bval.jsr.util.ToUnmodifiable; +import org.apache.bval.util.reflection.TypeUtils; + +public abstract class CascadableContainerD<P extends ElementD<?, ?>, E extends AnnotatedElement> extends + ElementD.NonRoot<P, E, MetadataReader.ForContainer<E>> implements CascadableDescriptor, ContainerDescriptor { + + private final boolean cascaded; + private final Set<GroupConversion> groupConversions; + private final Set<ContainerElementTypeD> containerElementTypes; + + protected CascadableContainerD(MetadataReader.ForContainer<E> reader, P parent) { + super(reader, parent); + cascaded = reader.isCascaded(); + groupConversions = reader.getGroupConversions(); + containerElementTypes = reader.getContainerElementTypes(this); + } + + @Override + public Class<?> getElementClass() { + return TypeUtils.getRawType(getGenericType(), parent.getElementClass()); + } + + @Override + public boolean isCascaded() { + return cascaded; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Set<GroupConversionDescriptor> getGroupConversions() { + return (Set) groupConversions; + } + + @Override + public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() { + return containerElementTypes.stream().filter(DescriptorManager::isConstrained) + .collect(ToUnmodifiable.set()); + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ComposedD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,127 @@ +/* + * 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.descriptor; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; + +import javax.validation.metadata.CascadableDescriptor; +import javax.validation.metadata.ConstraintDescriptor; +import javax.validation.metadata.ContainerDescriptor; +import javax.validation.metadata.ContainerElementTypeDescriptor; +import javax.validation.metadata.ElementDescriptor; +import javax.validation.metadata.GroupConversionDescriptor; +import javax.validation.metadata.PropertyDescriptor; + +import org.apache.bval.jsr.groups.GroupsComputer; +import org.apache.bval.jsr.util.ToUnmodifiable; +import org.apache.bval.util.Validate; + +public abstract class ComposedD<D extends ElementD<?, ?>> implements ElementDescriptor { + + static abstract class ForCascadableContainer<D extends CascadableContainerD<?, ?>> extends ComposedD<D> + implements CascadableDescriptor, ContainerDescriptor { + + ForCascadableContainer(List<D> delegates) { + super(delegates); + } + + @Override + public Set<ContainerElementTypeDescriptor> getConstrainedContainerElementTypes() { + return delegates.stream().map(ContainerDescriptor::getConstrainedContainerElementTypes) + .flatMap(Collection::stream).collect(ToUnmodifiable.set()); + } + + @Override + public boolean isCascaded() { + return delegates.stream().anyMatch(CascadableDescriptor::isCascaded); + } + + @Override + public Set<GroupConversionDescriptor> getGroupConversions() { + return delegates.stream().map(CascadableDescriptor::getGroupConversions).flatMap(Collection::stream) + .collect(ToUnmodifiable.set()); + } + } + + static class ForProperty extends ComposedD.ForCascadableContainer<PropertyD<?>> implements PropertyDescriptor { + + ForProperty(List<PropertyD<?>> delegates) { + super(delegates); + } + + @Override + public String getPropertyName() { + return delegates.stream().map(PropertyDescriptor::getPropertyName).findFirst() + .orElseThrow(IllegalStateException::new); + } + } + + public static <T extends ElementD<?, ?>> Stream<T> unwrap(ElementDescriptor descriptor, Class<T> delegateType) { + final Stream<?> s; + + if (descriptor instanceof ComposedD<?>) { + s = ((ComposedD<?>) descriptor).delegates.stream() + // unwrap recursively: + .flatMap(d -> unwrap(d, delegateType)); + } else { + s = Stream.of(descriptor); + } + return s.map(delegateType::cast); + } + + protected final List<D> delegates; + + ComposedD(List<D> delegates) { + super(); + this.delegates = delegates; + + Validate.notNull(delegates, "delegates"); + Validate.isTrue(!delegates.isEmpty(), "At least one delegate is required"); + Validate.isTrue(delegates.stream().noneMatch(Objects::isNull), "null delegates not permitted"); + } + + @Override + public boolean hasConstraints() { + return delegates.stream().anyMatch(ElementDescriptor::hasConstraints); + } + + @Override + public Class<?> getElementClass() { + return delegates.stream().map(ElementDescriptor::getElementClass).findFirst() + .orElseThrow(IllegalStateException::new); + } + + @Override + public Set<ConstraintDescriptor<?>> getConstraintDescriptors() { + return delegates.stream().map(ElementDescriptor::getConstraintDescriptors).flatMap(Collection::stream) + .collect(ToUnmodifiable.set()); + } + + @Override + public ConstraintFinder findConstraints() { + final GroupsComputer groupsComputer = + unwrap(this, ElementD.class).findFirst().orElseThrow(IllegalStateException::new).groupsComputer; + + return new Finder(groupsComputer, this); + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstraintD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,253 @@ +/* + * 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.descriptor; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Executable; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import javax.validation.ConstraintDeclarationException; +import javax.validation.ConstraintDefinitionException; +import javax.validation.ConstraintTarget; +import javax.validation.ConstraintValidator; +import javax.validation.Payload; +import javax.validation.ReportAsSingleViolation; +import javax.validation.ValidationException; +import javax.validation.metadata.ConstraintDescriptor; +import javax.validation.metadata.Scope; +import javax.validation.metadata.ValidateUnwrappedValue; +import javax.validation.valueextraction.Unwrapping; +import javax.validation.valueextraction.Unwrapping.Skip; +import javax.validation.valueextraction.Unwrapping.Unwrap; + +import org.apache.bval.jsr.ApacheValidatorFactory; +import org.apache.bval.jsr.ConstraintAnnotationAttributes; +import org.apache.bval.jsr.ConstraintAnnotationAttributes.Worker; +import org.apache.bval.jsr.metadata.Meta; +import org.apache.bval.jsr.util.AnnotationsManager; +import org.apache.bval.jsr.util.ToUnmodifiable; +import org.apache.bval.util.Exceptions; +import org.apache.bval.util.Lazy; +import org.apache.bval.util.Validate; + +public class ConstraintD<A extends Annotation> implements ConstraintDescriptor<A> { + private enum Optionality { + OPTIONAL, REQUIRED; + + public boolean isOptional() { + return this == Optionality.OPTIONAL; + } + } + + private static <T> Set<T> set(Supplier<T[]> array) { + return Stream.of(array.get()).collect(ToUnmodifiable.set()); + } + + private final A annotation; + private final Scope scope; + private final Meta<?> meta; + + private final Set<Class<? extends Payload>> payload; + private final Set<Class<?>> groups; + private final boolean reportAsSingle; + private final ValidateUnwrappedValue valueUnwrapping; + private final Map<String, Object> attributes; + private final ConstraintTarget validationAppliesTo; + + private final Set<ConstraintDescriptor<?>> composingConstraints; + private final List<Class<? extends ConstraintValidator<A, ?>>> constraintValidatorClasses; + private final Lazy<String> toString = + new Lazy<>(() -> String.format("%s: %s", ConstraintD.class.getSimpleName(), getAnnotation())); + + public ConstraintD(A annotation, Scope scope, Meta<?> meta, ApacheValidatorFactory validatorFactory) { + this.annotation = Validate.notNull(annotation, "annotation"); + this.scope = Validate.notNull(scope, "scope"); + this.meta = Validate.notNull(meta, "meta"); + + payload = computePayload(); + groups = set(() -> read(ConstraintAnnotationAttributes.GROUPS, Optionality.REQUIRED)); + reportAsSingle = annotation.annotationType().isAnnotationPresent(ReportAsSingleViolation.class); + valueUnwrapping = computeValidateUnwrappedValue(); + attributes = AnnotationsManager.readAttributes(annotation); + validationAppliesTo = computeValidationAppliesTo(meta.getElementType()); + + Validate.notNull(validatorFactory, "validatorFactory"); + composingConstraints = computeComposingConstraints(validatorFactory); + constraintValidatorClasses = computeConstraintValidatorClasses(validatorFactory); + } + + @Override + public A getAnnotation() { + return annotation; + } + + @Override + public Set<Class<?>> getGroups() { + return groups; + } + + @Override + public Set<Class<? extends Payload>> getPayload() { + return payload; + } + + @Override + public List<Class<? extends ConstraintValidator<A, ?>>> getConstraintValidatorClasses() { + return constraintValidatorClasses; + } + + @Override + public Map<String, Object> getAttributes() { + return attributes; + } + + @Override + public Set<ConstraintDescriptor<?>> getComposingConstraints() { + return composingConstraints; + } + + @Override + public boolean isReportAsSingleViolation() { + return reportAsSingle; + } + + @Override + public String getMessageTemplate() { + return read(ConstraintAnnotationAttributes.MESSAGE, Optionality.REQUIRED); + } + + @Override + public ConstraintTarget getValidationAppliesTo() { + return validationAppliesTo; + } + + @Override + public ValidateUnwrappedValue getValueUnwrapping() { + return valueUnwrapping; + } + + @Override + public <U> U unwrap(Class<U> type) throws ValidationException { + try { + return type.cast(this); + } catch (ClassCastException e) { + throw new ValidationException(e); + } + } + + public Scope getScope() { + return scope; + } + + public Class<?> getDeclaringClass() { + return meta.getDeclaringClass(); + } + + public ElementType getDeclaredOn() { + return meta.getElementType(); + } + + @Override + public String toString() { + return toString.get(); + } + + private <T> T read(ConstraintAnnotationAttributes attr) { + return read(attr, Optionality.OPTIONAL); + } + + private <T> T read(ConstraintAnnotationAttributes attr, Optionality optionality) { + final Class<? extends Annotation> constraintType = annotation.annotationType(); + final Optional<T> result = + Optional.of(constraintType).map(attr::analyze).filter(Worker::isValid).map(w -> w.<T> read(annotation)); + + Exceptions.raiseUnless(optionality.isOptional() || result.isPresent(), ConstraintDefinitionException::new, + "Required attribute %s missing from constraint type %s", + f -> f.args(attr.getAttributeName(), constraintType)); + + return result.orElse(null); + } + + private Set<ConstraintDescriptor<?>> computeComposingConstraints(ApacheValidatorFactory validatorFactory) { + return Stream.of(validatorFactory.getAnnotationsManager().getComposingConstraints(annotation)) + .map(c -> new ConstraintD<>(c, scope, meta, validatorFactory)).collect(ToUnmodifiable.set()); + } + + @SuppressWarnings("unchecked") + private List<Class<? extends ConstraintValidator<A, ?>>> computeConstraintValidatorClasses( + ApacheValidatorFactory validatorFactory) { + return validatorFactory.getConstraintsCache() + .getConstraintValidatorClasses((Class<A>) annotation.annotationType()); + } + + private ValidateUnwrappedValue computeValidateUnwrappedValue() { + final Set<Class<? extends Payload>> p = getPayload(); + final boolean unwrap = p.contains(Unwrap.class); + final boolean skip = p.contains(Skip.class); + if (unwrap) { + Validate.validState(!skip, "Cannot specify both %s and %s", Unwrap.class.getSimpleName(), + Skip.class.getSimpleName()); + return ValidateUnwrappedValue.UNWRAP; + } + return skip ? ValidateUnwrappedValue.SKIP : ValidateUnwrappedValue.DEFAULT; + } + + private Set<Class<? extends Payload>> computePayload() { + final Set<Class<? extends Payload>> result = + set(() -> read(ConstraintAnnotationAttributes.PAYLOAD, Optionality.REQUIRED)); + if (result.containsAll(Arrays.asList(Unwrapping.Unwrap.class, Unwrapping.Skip.class))) { + Exceptions.raise(ConstraintDeclarationException::new, + "Constraint %s declared at %s specifies conflicting value unwrapping hints", annotation, + meta.getHost()); + } + return result; + } + + private ConstraintTarget computeValidationAppliesTo(ElementType elementType) { + final ConstraintTarget result = read(ConstraintAnnotationAttributes.VALIDATION_APPLIES_TO); + if (result != null && result != ConstraintTarget.IMPLICIT) { + final AnnotatedElement host = meta.getHost(); + Exceptions.raiseUnless(host instanceof Executable, ConstraintDeclarationException::new, "Illegal %s on %s", + result, host); + + switch (result) { + case PARAMETERS: + Exceptions.raiseIf(((Executable) host).getParameterCount() == 0, ConstraintDeclarationException::new, + "Illegal specification of %s on %s with no parameters", result, elementType); + break; + case RETURN_VALUE: + Exceptions.raiseIf(Void.TYPE.equals(meta.getType()), ConstraintDeclarationException::new, + "Illegal %s on %s method %s", result, Void.TYPE, host); + break; + default: + Exceptions.raise(IllegalStateException::new, "Unknown %s %s", ConstraintTarget.class.getSimpleName(), + result); + } + } + return result; + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ConstructorD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,36 @@ +/* + * 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.descriptor; + +import java.lang.reflect.Constructor; + +import javax.validation.metadata.ConstructorDescriptor; + +public class ConstructorD<T> extends ExecutableD<Constructor<? extends T>, MetadataReader.ForConstructor<T>, ConstructorD<T>> + implements ConstructorDescriptor { + + ConstructorD(MetadataReader.ForConstructor<T> reader, BeanD<T> parent) { + super(reader, parent); + } + + @Override + public Class<?> getElementClass() { + return getParent().getElementClass(); + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ContainerElementTypeD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,52 @@ +/* + * 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.descriptor; + +import java.lang.reflect.AnnotatedType; + +import javax.validation.metadata.ContainerElementTypeDescriptor; + +import org.apache.bval.jsr.metadata.ContainerElementKey; +import org.apache.bval.util.Validate; + +public class ContainerElementTypeD extends CascadableContainerD<CascadableContainerD<?, ?>, AnnotatedType> + implements ContainerElementTypeDescriptor { + + private final ContainerElementKey key; + + ContainerElementTypeD(ContainerElementKey key, MetadataReader.ForContainer<AnnotatedType> reader, + CascadableContainerD<?, ?> parent) { + super(reader, parent); + this.key = Validate.notNull(key, "key"); + } + + @Override + public Class<?> getContainerClass() { + return key.getContainerClass(); + } + + @Override + public Integer getTypeArgumentIndex() { + return Integer.valueOf(key.getTypeArgumentIndex()); + } + + public ContainerElementKey getKey() { + return key; + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/CrossParameterD.java Fri Oct 12 15:00:48 2018 @@ -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.jsr.descriptor; + +import java.lang.reflect.Executable; + +import javax.validation.metadata.CrossParameterDescriptor; + +public class CrossParameterD<P extends ExecutableD<?, ?, P>, E extends Executable> + extends ElementD.NonRoot<P, E, MetadataReader.ForElement<E, ?>> implements CrossParameterDescriptor { + + protected CrossParameterD(MetadataReader.ForElement<E, ?> reader, P parent) { + super(reader, parent); + } + + @Override + public Class<?> getElementClass() { + return Object[].class; + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,110 @@ +/* + * 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.descriptor; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.validation.metadata.BeanDescriptor; +import javax.validation.metadata.CascadableDescriptor; +import javax.validation.metadata.ContainerDescriptor; +import javax.validation.metadata.ElementDescriptor; +import javax.validation.metadata.ExecutableDescriptor; + +import org.apache.bval.jsr.ApacheValidatorFactory; +import org.apache.bval.jsr.metadata.AnnotationBehaviorMergeStrategy; +import org.apache.bval.jsr.metadata.CompositeBuilder; +import org.apache.bval.jsr.metadata.DualBuilder; +import org.apache.bval.jsr.metadata.HierarchyBuilder; +import org.apache.bval.jsr.metadata.MetadataBuilder; +import org.apache.bval.jsr.metadata.ReflectionBuilder; +import org.apache.bval.util.Validate; + +public class DescriptorManager { + public static <D extends ElementDescriptor & CascadableDescriptor & ContainerDescriptor> boolean isConstrained( + D descriptor) { + return descriptor != null && (descriptor.hasConstraints() || descriptor.isCascaded() + || !descriptor.getConstrainedContainerElementTypes().isEmpty()); + } + + public static <D extends ElementDescriptor & CascadableDescriptor & ContainerDescriptor> boolean isCascaded( + D descriptor) { + return descriptor != null && (descriptor.isCascaded() + || descriptor.getConstrainedContainerElementTypes().stream().anyMatch(DescriptorManager::isCascaded)); + } + + public static <E extends ExecutableDescriptor> boolean isConstrained(E descriptor) { + return descriptor != null && (descriptor.hasConstrainedParameters() || descriptor.hasConstrainedReturnValue()); + } + + private final ApacheValidatorFactory validatorFactory; + private final ConcurrentMap<Class<?>, BeanD<?>> beanDescriptors = new ConcurrentHashMap<>(); + private final ReflectionBuilder reflectionBuilder; + + public DescriptorManager(ApacheValidatorFactory validatorFactory) { + super(); + this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory"); + this.reflectionBuilder = new ReflectionBuilder(validatorFactory); + } + + public <T> BeanDescriptor getBeanDescriptor(Class<T> beanClass) { + Validate.notNull(beanClass, IllegalArgumentException::new, "beanClass"); + + // cannot use computeIfAbsent due to recursion being the usual case: + if (beanDescriptors.containsKey(beanClass)) { + return beanDescriptors.get(beanClass); + } + final MetadataReader.ForBean<T> reader = + new MetadataReader(validatorFactory, beanClass).forBean(builder(beanClass)); + final BeanD<T> beanD = new BeanD<>(reader); + @SuppressWarnings("unchecked") + final BeanD<T> result = + Optional.ofNullable((BeanD<T>) beanDescriptors.putIfAbsent(beanClass, beanD)).orElse(beanD); + return result; + } + + public void clear() { + beanDescriptors.clear(); + } + + private <T> MetadataBuilder.ForBean<T> builder(Class<T> beanClass) { + final MetadataBuilder.ForBean<T> primaryBuilder = + new HierarchyBuilder(validatorFactory, reflectionBuilder::forBean).forBean(beanClass); + + final MetadataBuilder.ForBean<T> customBuilder = + new HierarchyBuilder(validatorFactory, this::customBuilder).forBean(beanClass); + + return customBuilder.isEmpty() ? primaryBuilder + : DualBuilder.forBean(beanClass, primaryBuilder, customBuilder, validatorFactory); + } + + private <T> MetadataBuilder.ForBean<T> customBuilder(Class<T> beanClass) { + final List<MetadataBuilder.ForBean<T>> customBuilders = + validatorFactory.getMetadataBuilders().getCustomBuilders(beanClass); + + if (customBuilders.isEmpty()) { + return null; + } + if (customBuilders.size() == 1) { + return customBuilders.get(0); + } + return customBuilders.stream() + .collect(CompositeBuilder.with(validatorFactory, AnnotationBehaviorMergeStrategy.consensus()).compose()); + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ElementD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,128 @@ +/* + * 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.descriptor; + +import java.lang.annotation.ElementType; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Map; +import java.util.Set; + +import javax.validation.metadata.ConstraintDescriptor; +import javax.validation.metadata.ElementDescriptor; + +import org.apache.bval.jsr.groups.GroupStrategy; +import org.apache.bval.jsr.groups.GroupsComputer; +import org.apache.bval.jsr.metadata.Meta; +import org.apache.bval.util.Validate; +import org.apache.bval.util.reflection.TypeUtils; + +public abstract class ElementD<E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>> + implements ElementDescriptor { + + public static abstract class NonRoot<P extends ElementD<?, ?>, E extends AnnotatedElement, R extends MetadataReader.ForElement<E, ?>> + extends ElementD<E, R> { + + protected final P parent; + + protected NonRoot(R reader, P parent) { + super(reader); + this.parent = Validate.notNull(parent, "parent"); + } + + public P getParent() { + return parent; + } + + @Override + public final Type getGenericType() { + if (TypeUtils.containsTypeVariables(genericType)) { + final Map<TypeVariable<?>, Type> args = + TypeUtils.getTypeArguments(parent.getGenericType(), Object.class); + return TypeUtils.unrollVariables(args, genericType); + } + return genericType; + } + + @Override + final protected BeanD<?> getBean() { + return parent.getBean(); + } + + @Override + public final GroupStrategy getGroupStrategy() { + return getBean().getGroupStrategy(); + } + } + + protected final Type genericType; + final GroupsComputer groupsComputer; + + private final Meta<E> meta; + private final Set<ConstraintD<?>> constraints; + + protected ElementD(R reader) { + super(); + Validate.notNull(reader, "reader"); + this.meta = reader.meta; + this.genericType = reader.meta.getType(); + this.constraints = reader.getConstraints(); + this.groupsComputer = reader.getValidatorFactory().getGroupsComputer(); + } + + @Override + public final boolean hasConstraints() { + return !constraints.isEmpty(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public final Set<ConstraintDescriptor<?>> getConstraintDescriptors() { + return (Set) constraints; + } + + @Override + public final ConstraintFinder findConstraints() { + return new Finder(groupsComputer, this); + } + + public final ElementType getElementType() { + return meta.getElementType(); + } + + public final E getTarget() { + return meta.getHost(); + } + + public final Class<?> getDeclaringClass() { + return meta.getDeclaringClass(); + } + + public abstract Type getGenericType(); + + public abstract GroupStrategy getGroupStrategy(); + + @Override + public String toString() { + return String.format("%s: %s", getClass().getSimpleName(), meta.describeHost()); + } + + protected abstract BeanD<?> getBean(); +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ExecutableD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,78 @@ +/* + * 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.descriptor; + +import java.lang.reflect.Executable; +import java.util.List; + +import javax.validation.metadata.CrossParameterDescriptor; +import javax.validation.metadata.ExecutableDescriptor; +import javax.validation.metadata.ParameterDescriptor; +import javax.validation.metadata.ReturnValueDescriptor; + +public abstract class ExecutableD<E extends Executable, R extends MetadataReader.ForExecutable<E, R>, SELF extends ExecutableD<E, R, SELF>> + extends ElementD.NonRoot<BeanD<?>, E, R> implements ExecutableDescriptor { + + private final String name; + private final ReturnValueD<SELF, E> returnValue; + private final List<ParameterD<SELF>> parameters; + private final CrossParameterD<SELF, E> crossParameter; + + @SuppressWarnings("unchecked") + protected ExecutableD(R reader, BeanD<?> parent) { + super(reader, parent); + + name = reader.meta.getName(); + + returnValue = reader.getReturnValueDescriptor((SELF) this); + parameters = reader.getParameterDescriptors((SELF) this); + crossParameter = reader.getCrossParameterDescriptor((SELF) this); + } + + @Override + public final String getName() { + return name; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public final List<ParameterDescriptor> getParameterDescriptors() { + return (List) parameters; + } + + @Override + public final CrossParameterDescriptor getCrossParameterDescriptor() { + return crossParameter; + } + + @Override + public final ReturnValueDescriptor getReturnValueDescriptor() { + return returnValue; + } + + @Override + public final boolean hasConstrainedParameters() { + return parameters.stream().anyMatch(DescriptorManager::isConstrained) || getCrossParameterDescriptor().hasConstraints(); + } + + @Override + public final boolean hasConstrainedReturnValue() { + return DescriptorManager.isConstrained(returnValue); + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/Finder.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,150 @@ +/* + * 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.descriptor; + +import java.lang.annotation.ElementType; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.validation.GroupDefinitionException; +import javax.validation.GroupSequence; +import javax.validation.groups.Default; +import javax.validation.metadata.ConstraintDescriptor; +import javax.validation.metadata.ElementDescriptor; +import javax.validation.metadata.ElementDescriptor.ConstraintFinder; +import javax.validation.metadata.Scope; + +import org.apache.bval.jsr.groups.Group; +import org.apache.bval.jsr.groups.Groups; +import org.apache.bval.jsr.groups.GroupsComputer; +import org.apache.bval.jsr.util.ToUnmodifiable; +import org.apache.bval.util.Exceptions; +import org.apache.bval.util.Lazy; +import org.apache.bval.util.Validate; + +class Finder implements ConstraintFinder { + private static Stream<Group> allGroups(Groups groups) { + return Stream.concat(groups.getGroups().stream(), + groups.getSequences().stream().map(Group.Sequence::getGroups).flatMap(Collection::stream)); + } + + private volatile Predicate<ConstraintD<?>> groups = c -> true; + private volatile Predicate<ConstraintD<?>> scope; + private volatile Predicate<ConstraintD<?>> elements; + + private final GroupsComputer groupsComputer; + private final ElementDescriptor owner; + private final Lazy<Groups> getDefaultSequence = new Lazy<>(this::computeDefaultSequence); + private final Lazy<Class<?>> beanClass; + + Finder(GroupsComputer groupsComputer, ElementDescriptor owner) { + this.groupsComputer = Validate.notNull(groupsComputer, "groupsComputer"); + this.owner = Validate.notNull(owner, "owner"); + this.beanClass = new Lazy<>(() -> firstAtomicElementDescriptor().getBean().getElementClass()); + } + + @Override + public ConstraintFinder unorderedAndMatchingGroups(Class<?>... groups) { + final Set<Class<?>> allGroups = computeAll(groups); + this.groups = c -> !Collections.disjoint(allGroups, c.getGroups()); + return this; + } + + @Override + public ConstraintFinder lookingAt(Scope scope) { + this.scope = scope == Scope.HIERARCHY ? null : c -> c.getScope() == scope; + return this; + } + + @Override + public ConstraintFinder declaredOn(ElementType... types) { + this.elements = c -> Stream.of(types).filter(Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(ElementType.class))).contains(c.getDeclaredOn()); + + return this; + } + + @Override + public Set<ConstraintDescriptor<?>> getConstraintDescriptors() { + return getConstraints().filter(filter()).collect(ToUnmodifiable.set()); + } + + @Override + public boolean hasConstraints() { + return getConstraints().anyMatch(filter()); + } + + private Stream<ConstraintD<?>> getConstraints() { + return owner.getConstraintDescriptors().stream().<ConstraintD<?>> map(c -> c.unwrap(ConstraintD.class)); + } + + private Predicate<ConstraintD<?>> filter() { + Predicate<ConstraintD<?>> result = groups; + if (scope != null) { + result = result.and(scope); + } + if (elements != null) { + result = result.and(elements); + } + return result; + } + + private ElementD<?,?> firstAtomicElementDescriptor() { + return ComposedD.unwrap(owner, ElementD.class).findFirst().orElseThrow(IllegalStateException::new); + } + + private Groups computeDefaultSequence() { + final ElementD<?, ?> element = firstAtomicElementDescriptor(); + Collection<Class<?>> redef = + element.getGroupStrategy().getGroups().stream().map(Group::getGroup).collect(Collectors.toList()); + + if (redef == null) { + return GroupsComputer.DEFAULT_GROUPS; + } + final Class<?> t = this.beanClass.get(); + if (redef.contains(Default.class)) { + Exceptions.raise(GroupDefinitionException::new, "%s for %s cannot include %s.class", + GroupSequence.class.getSimpleName(), t, Default.class.getSimpleName()); + } + redef = redef.stream() + .map(substituteDefaultGroup()) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + return groupsComputer.computeGroups(redef); + } + + private Set<Class<?>> computeAll(Class<?>[] groups) { + final Groups preliminaryGroups = groupsComputer.computeGroups(Stream.of(groups).map(substituteDefaultGroup())); + return allGroups(preliminaryGroups) + .flatMap(g -> g.isDefault() ? allGroups(getDefaultSequence.get()) : Stream.of(g)).map(Group::getGroup) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } + + private UnaryOperator<Class<?>> substituteDefaultGroup() { + return t -> t.isAssignableFrom(beanClass.get()) ? Default.class : t; + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MetadataReader.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,412 @@ +/* + * 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.descriptor; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import javax.validation.ConstraintDeclarationException; +import javax.validation.GroupDefinitionException; +import javax.validation.GroupSequence; +import javax.validation.ParameterNameProvider; +import javax.validation.Valid; +import javax.validation.groups.ConvertGroup; +import javax.validation.groups.Default; +import javax.validation.metadata.PropertyDescriptor; +import javax.validation.metadata.Scope; + +import org.apache.bval.jsr.ApacheValidatorFactory; +import org.apache.bval.jsr.ConstraintAnnotationAttributes; +import org.apache.bval.jsr.groups.Group; +import org.apache.bval.jsr.groups.GroupConversion; +import org.apache.bval.jsr.groups.GroupStrategy; +import org.apache.bval.jsr.groups.GroupsComputer; +import org.apache.bval.jsr.metadata.ContainerElementKey; +import org.apache.bval.jsr.metadata.EmptyBuilder; +import org.apache.bval.jsr.metadata.Meta; +import org.apache.bval.jsr.metadata.MetadataBuilder; +import org.apache.bval.jsr.metadata.Signature; +import org.apache.bval.jsr.util.AnnotationsManager; +import org.apache.bval.jsr.util.Methods; +import org.apache.bval.jsr.util.ToUnmodifiable; +import org.apache.bval.jsr.xml.AnnotationProxyBuilder; +import org.apache.bval.util.Exceptions; +import org.apache.bval.util.ObjectUtils; +import org.apache.bval.util.Validate; +import org.apache.bval.util.reflection.Reflection; +import org.apache.bval.util.reflection.Reflection.Interfaces; +import org.apache.commons.weaver.privilizer.Privilizing; +import org.apache.commons.weaver.privilizer.Privilizing.CallTo; + +@Privilizing(@CallTo(Reflection.class)) +class MetadataReader { + + class ForElement<E extends AnnotatedElement, B extends MetadataBuilder.ForElement<E>> { + final Meta<E> meta; + protected final B builder; + + ForElement(Meta<E> meta, B builder) { + super(); + this.meta = Validate.notNull(meta, "meta"); + this.builder = Validate.notNull(builder, "builder"); + } + + Set<ConstraintD<?>> getConstraints() { + return builder.getConstraintDeclarationMap(meta).entrySet().stream().filter(e -> e.getValue().length > 0) + .flatMap(e -> { + final Meta<E> m = e.getKey(); + final Class<?> declaredBy = m.getDeclaringClass(); + final Scope scope = declaredBy.equals(beanClass) ? Scope.LOCAL_ELEMENT : Scope.HIERARCHY; + return Stream.of(e.getValue()).peek( + c -> validatorFactory.getAnnotationsManager().validateConstraintDefinition(c.annotationType())) + .map(c -> rewriteConstraint(c, declaredBy)) + .map(c -> new ConstraintD<>(c, scope, m, validatorFactory)); + }).collect(ToUnmodifiable.set()); + } + + ApacheValidatorFactory getValidatorFactory() { + return validatorFactory; + } + + private <A extends Annotation> A rewriteConstraint(A constraint, Class<?> declaredBy) { + boolean mustRewrite = false; + Class<?>[] groups = + ConstraintAnnotationAttributes.GROUPS.analyze(constraint.annotationType()).read(constraint); + if (groups.length == 0) { + mustRewrite = true; + groups = GroupsComputer.DEFAULT_GROUP; + } + if (!(declaredBy.equals(beanClass) || beanClass.isInterface())) { + if (ObjectUtils.arrayContains(groups, Default.class) + && !ObjectUtils.arrayContains(groups, declaredBy)) { + mustRewrite = true; + groups = ObjectUtils.arrayAdd(groups, declaredBy); + } + } + if (mustRewrite) { + final AnnotationProxyBuilder<A> builder = new AnnotationProxyBuilder<A>(constraint); + builder.setGroups(groups); + return builder.createAnnotation(); + } + return constraint; + } + } + + class ForBean<T> extends MetadataReader.ForElement<Class<T>, MetadataBuilder.ForClass<T>> { + private final MetadataBuilder.ForBean<T> beanBuilder; + + ForBean(Meta<Class<T>> meta, MetadataBuilder.ForBean<T> builder) { + super(meta, Validate.notNull(builder, "builder").getClass(meta)); + this.beanBuilder = builder; + } + + Map<String, PropertyDescriptor> getProperties(BeanD<T> parent) { + final Map<String, List<PropertyD<?>>> properties = new LinkedHashMap<>(); + final Function<? super String, ? extends List<PropertyD<?>>> descriptorList = k -> new ArrayList<>(); + + beanBuilder.getFields(meta).forEach((f, builder) -> { + final Field fld = Reflection.find(meta.getHost(), t -> Reflection.getDeclaredField(t, f)); + properties.computeIfAbsent(f, descriptorList).add( + new PropertyD.ForField(new MetadataReader.ForContainer<>(new Meta.ForField(fld), builder), parent)); + }); + beanBuilder.getGetters(meta).forEach((g, builder) -> { + final Method getter = Methods.getter(meta.getHost(), g); + + if (getter == null) { + Exceptions.raise(IllegalStateException::new, "Getter method for property %s not found", g); + } + properties.computeIfAbsent(g, descriptorList).add(new PropertyD.ForMethod( + new MetadataReader.ForContainer<>(new Meta.ForMethod(getter), builder), parent)); + }); + return properties.entrySet().stream().collect(ToUnmodifiable.map(Map.Entry::getKey, e -> { + final List<PropertyD<?>> delegates = e.getValue(); + + if (delegates.size() == 1) { + return delegates.get(0); + } + final Set<PropertyD<?>> constrained = + delegates.stream().filter(DescriptorManager::isConstrained).collect(Collectors.toSet()); + if (constrained.isEmpty()) { + return delegates.get(0); + } + if (constrained.size() == 1) { + return constrained.iterator().next(); + } + return new ComposedD.ForProperty(delegates); + })); + } + + Map<Signature, MethodD> getMethods(BeanD<T> parent) { + final Map<Signature, MetadataBuilder.ForExecutable<Method>> methodBuilders = beanBuilder.getMethods(meta); + if (methodBuilders.isEmpty()) { + return Collections.emptyMap(); + } + final Map<Signature, MethodD> result = new LinkedHashMap<>(); + + methodBuilders.forEach((sig, builder) -> { + final Method m = Reflection.find(meta.getHost(), + t -> Reflection.getDeclaredMethod(t, sig.getName(), sig.getParameterTypes())); + + final MethodD descriptor = + new MethodD(new MetadataReader.ForMethod(new Meta.ForMethod(m), builder), parent); + if (DescriptorManager.isConstrained(descriptor)) { + result.put(sig, descriptor); + } + }); + return Collections.unmodifiableMap(result); + } + + Map<Signature, ConstructorD<T>> getConstructors(BeanD<T> parent) { + final Map<Signature, MetadataBuilder.ForExecutable<Constructor<? extends T>>> ctorBuilders = + beanBuilder.getConstructors(meta); + + if (ctorBuilders.isEmpty()) { + return Collections.emptyMap(); + } + final Map<Signature, ConstructorD<T>> result = new LinkedHashMap<>(); + + ctorBuilders.forEach((sig, builder) -> { + final Constructor<?> c = Reflection.getDeclaredConstructor(meta.getHost(), sig.getParameterTypes()); + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Meta.ForConstructor<T> metaCtor = (Meta.ForConstructor) new Meta.ForConstructor<>(c); + final ConstructorD<T> descriptor = + new ConstructorD<>(new MetadataReader.ForConstructor<T>(metaCtor, builder), parent); + if (DescriptorManager.isConstrained(descriptor)) { + result.put(sig, descriptor); + } + }); + return Collections.unmodifiableMap(result); + } + + GroupStrategy getGroupStrategy() { + final Class<T> host = meta.getHost(); + if (host.isInterface()) { + return validatorFactory.getGroupsComputer().computeGroups(host).asStrategy(); + } + final GroupStrategy parentStrategy = Optional.ofNullable(host.getSuperclass()).filter(JDK.negate()) + .map(validatorFactory.getDescriptorManager()::getBeanDescriptor).map(BeanD.class::cast) + .map(BeanD::getGroupStrategy).orElse(null); + + final List<Class<?>> groupSequence = builder.getGroupSequence(meta); + + final Set<Group> parentGroups = parentStrategy == null ? null : parentStrategy.getGroups(); + + Group localGroup = Group.of(host); + if (groupSequence == null) { + final Set<Group> groups = new HashSet<>(); + groups.add(localGroup); + + for (Class<?> t : Reflection.hierarchy(host, Interfaces.INCLUDE)) { + if (JDK.test(t)) { + continue; + } + if (!t.isInterface()) { + continue; + } + if (AnnotationsManager.isAnnotationDirectlyPresent(t, GroupSequence.class)) { + continue; + } + final Group g = Group.of(t); + if (parentGroups != null && parentGroups.contains(g)) { + continue; + } + groups.add(g); + } + final GroupStrategy strategy = GroupStrategy.simple(groups); + return parentStrategy == null ? strategy : GroupStrategy.composite(strategy, parentStrategy); + } + if (groupSequence.contains(Default.class)) { + Exceptions.raise(GroupDefinitionException::new, "@%s for %s must not contain %s", + GroupSequence.class.getSimpleName(), host, Default.class.getName()); + } + if (!groupSequence.contains(host)) { + Exceptions.raise(GroupDefinitionException::new, "@%s for %s must contain %<s", + GroupSequence.class.getSimpleName(), host); + } + final Group.Sequence result = + Group.sequence(groupSequence.stream().map(Group::of).collect(Collectors.toList())); + + final Deque<Group> expanded = new ArrayDeque<>(); + for (Class<?> t : Reflection.hierarchy(host, Interfaces.INCLUDE)) { + if (JDK.test(t)) { + continue; + } + if (t.isInterface() && AnnotationsManager.isAnnotationDirectlyPresent(t, GroupSequence.class)) { + continue; + } + expanded.push(Group.of(t)); + } + if (expanded.size() == 1) { + return result; + } + return result.redefining(Collections.singletonMap(localGroup, GroupStrategy.simple(expanded))); + } + } + + class ForContainer<E extends AnnotatedElement> extends ForElement<E, MetadataBuilder.ForContainer<E>> { + + ForContainer(Meta<E> meta, MetadataBuilder.ForContainer<E> builder) { + super(meta, builder); + } + + boolean isCascaded() { + return builder.isCascade(meta); + } + + Set<GroupConversion> getGroupConversions() { + final Set<GroupConversion> groupConversions = builder.getGroupConversions(meta); + if (!groupConversions.isEmpty()) { + if (!isCascaded()) { + Exceptions.raise(ConstraintDeclarationException::new, "@%s declared without @%s on %s", + ConvertGroup.class.getSimpleName(), Valid.class.getSimpleName(), meta.describeHost()); + } + if (groupConversions.stream().map(GroupConversion::getFrom).distinct().count() < groupConversions + .size()) { + Exceptions.raise(ConstraintDeclarationException::new, "%s has duplicate 'from' group conversions", + meta.describeHost()); + } + groupConversions.stream().map(GroupConversion::getFrom) + .forEach(from -> Exceptions.raiseIf(from.isAnnotationPresent(GroupSequence.class), + ConstraintDeclarationException::new, + "Invalid group conversion declared on %s from group sequence %s", + f -> f.args(meta.describeHost(), from))); + } + return groupConversions; + } + + Set<ContainerElementTypeD> getContainerElementTypes(CascadableContainerD<?, ?> parent) { + final Map<ContainerElementKey, MetadataBuilder.ForContainer<AnnotatedType>> containerElementTypes = + builder.getContainerElementTypes(meta); + + if (containerElementTypes.isEmpty()) { + return Collections.emptySet(); + } + final Set<ContainerElementTypeD> result = + new TreeSet<>(Comparator.comparing(ContainerElementTypeD::getKey)); + + containerElementTypes.forEach((k, builder) -> { + result.add(new ContainerElementTypeD(k, + new MetadataReader.ForContainer<>(new Meta.ForContainerElement(meta, k), builder), parent)); + }); + return Collections.unmodifiableSet(result); + } + } + + abstract class ForExecutable<E extends Executable, SELF extends ForExecutable<E, SELF>> + extends ForElement<E, MetadataBuilder.ForElement<E>> { + private final MetadataBuilder.ForExecutable<E> executableBuilder; + + ForExecutable(Meta<E> meta, MetadataBuilder.ForExecutable<E> executableBuilder) { + super(meta, EmptyBuilder.instance().forElement()); + this.executableBuilder = Validate.notNull(executableBuilder, "executableBuilder"); + } + + <X extends ExecutableD<E, SELF, X>> List<ParameterD<X>> getParameterDescriptors(X parent) { + final Parameter[] parameters = meta.getHost().getParameters(); + + final List<String> parameterNames = + getParameterNames(validatorFactory.getParameterNameProvider(), meta.getHost()); + + final List<MetadataBuilder.ForContainer<Parameter>> builders = executableBuilder.getParameters(meta); + + return IntStream.range(0, parameters.length).mapToObj(i -> { + final Meta.ForParameter param = new Meta.ForParameter(parameters[i], parameterNames.get(i)); + final MetadataBuilder.ForContainer<Parameter> parameterBuilder = + builders.size() > i ? builders.get(i) : EmptyBuilder.instance().forContainer(); + return new ParameterD<>(param, i, new MetadataReader.ForContainer<>(param, parameterBuilder), parent); + }).collect(ToUnmodifiable.list()); + } + + <X extends ExecutableD<E, SELF, X>> CrossParameterD<X, E> getCrossParameterDescriptor(X parent) { + final Meta.ForCrossParameter<E> cp = new Meta.ForCrossParameter<>(meta); + return new CrossParameterD<>(new MetadataReader.ForElement<>(cp, executableBuilder.getCrossParameter(cp)), + parent); + } + + <X extends ExecutableD<E, SELF, X>> ReturnValueD<X, E> getReturnValueDescriptor(X parent) { + return new ReturnValueD<>(new MetadataReader.ForContainer<>(meta, executableBuilder.getReturnValue(meta)), + parent); + } + + abstract List<String> getParameterNames(ParameterNameProvider parameterNameProvider, E host); + } + + class ForMethod extends ForExecutable<Method, ForMethod> { + ForMethod(Meta<Method> meta, MetadataBuilder.ForExecutable<Method> builder) { + super(meta, builder); + } + + @Override + List<String> getParameterNames(ParameterNameProvider parameterNameProvider, Method host) { + return parameterNameProvider.getParameterNames(host); + } + } + + class ForConstructor<T> extends ForExecutable<Constructor<? extends T>, ForConstructor<T>> { + + ForConstructor(Meta<Constructor<? extends T>> meta, + MetadataBuilder.ForExecutable<Constructor<? extends T>> builder) { + super(meta, builder); + } + + @Override + List<String> getParameterNames(ParameterNameProvider parameterNameProvider, Constructor<? extends T> host) { + return parameterNameProvider.getParameterNames(host); + } + } + + private static final Predicate<Class<?>> JDK = t -> t.getName().startsWith("java."); + + private final ApacheValidatorFactory validatorFactory; + private final Class<?> beanClass; + + MetadataReader(ApacheValidatorFactory validatorFactory, Class<?> beanClass) { + super(); + this.validatorFactory = Validate.notNull(validatorFactory, "validatorFactory"); + this.beanClass = Validate.notNull(beanClass, "beanClass"); + } + + @SuppressWarnings("unchecked") + <T> MetadataReader.ForBean<T> forBean(MetadataBuilder.ForBean<T> builder) { + return new MetadataReader.ForBean<>(new Meta.ForClass<>((Class<T>) beanClass), builder); + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/MethodD.java Fri Oct 12 15:00:48 2018 @@ -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.jsr.descriptor; + +import java.lang.reflect.Method; + +import javax.validation.metadata.MethodDescriptor; +import javax.validation.metadata.MethodType; + +import org.apache.bval.jsr.util.Methods; + +class MethodD extends ExecutableD<Method, MetadataReader.ForMethod, MethodD> implements MethodDescriptor { + private final MethodType methodType; + + MethodD(MetadataReader.ForMethod reader, BeanD<?> parent) { + super(reader, parent); + methodType = Methods.isGetter(reader.meta.getHost()) ? MethodType.GETTER : MethodType.NON_GETTER; + } + + @Override + public Class<?> getElementClass() { + return getTarget().getReturnType(); + } + + MethodType getMethodType() { + return methodType; + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/ParameterD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,92 @@ +/* + * 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.descriptor; + +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; + +import javax.validation.metadata.ParameterDescriptor; + +import org.apache.bval.jsr.metadata.Meta; +import org.apache.bval.util.Validate; +import org.apache.bval.util.reflection.TypeUtils; + +public class ParameterD<P extends ExecutableD<?, ?, P>> extends CascadableContainerD<P, Parameter> + implements ParameterDescriptor { + + private final int index; + private final String name; + private final Class<?> type; + + ParameterD(Meta.ForParameter meta, int index, MetadataReader.ForContainer<Parameter> reader, P parent) { + super(reader, parent); + + Validate.isTrue(index >= 0 && index < meta.getHost().getDeclaringExecutable().getParameterCount(), + "Invalid parameter index %d", index); + + this.index = index; + + name = reader.meta.getName(); + type = resolveType(); + } + + @Override + public Class<?> getElementClass() { + return type; + } + + @Override + public int getIndex() { + return index; + } + + @Override + public String getName() { + return name; + } + + private Class<?> resolveType() { + final Class<?> declaringClass = getTarget().getDeclaringExecutable().getDeclaringClass(); + + Type t = getTarget().getParameterizedType(); + + int arrayDepth = 0; + while (t instanceof GenericArrayType) { + arrayDepth++; + t = ((GenericArrayType) t).getGenericComponentType(); + } + + Class<?> result = null; + + while (result == null) { + result = TypeUtils.getRawType(t, declaringClass); + if (result != null) { + break; + } + if (t instanceof TypeVariable<?>) { + final TypeVariable<?> tv = (TypeVariable<?>) t; + t = tv.getBounds()[0]; + } + } + return arrayDepth > 0 ? Array.newInstance(result, new int[arrayDepth]).getClass() : result; + } +} Added: tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java URL: http://svn.apache.org/viewvc/tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java?rev=1843674&view=auto ============================================================================== --- tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java (added) +++ tomee/deps/branches/bval-2/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/PropertyD.java Fri Oct 12 15:00:48 2018 @@ -0,0 +1,112 @@ +/* + * 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.descriptor; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.stream.Stream; + +import javax.validation.ValidationException; +import javax.validation.metadata.PropertyDescriptor; + +import org.apache.bval.jsr.GraphContext; +import org.apache.bval.jsr.util.Methods; +import org.apache.bval.jsr.util.PathImpl; +import org.apache.bval.util.Validate; +import org.apache.bval.util.reflection.Reflection; +import org.apache.commons.weaver.privilizer.Privilizing; +import org.apache.commons.weaver.privilizer.Privilizing.CallTo; + +@Privilizing(@CallTo(Reflection.class)) +public abstract class PropertyD<E extends AnnotatedElement> extends CascadableContainerD<BeanD<?>, E> + implements PropertyDescriptor { + + static class ForField extends PropertyD<Field> { + + ForField(MetadataReader.ForContainer<Field> reader, BeanD<?> parent) { + super(reader, parent); + } + + @Override + public String getPropertyName() { + return getTarget().getName(); + } + + @Override + public Object getValue(Object parent) throws Exception { + final boolean mustUnset = Reflection.setAccessible(getTarget(), true); + try { + return getTarget().get(parent); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } finally { + if (mustUnset) { + Reflection.setAccessible(getTarget(), false); + } + } + } + } + + static class ForMethod extends PropertyD<Method> { + + ForMethod(MetadataReader.ForContainer<Method> reader, BeanD<?> parent) { + super(reader, parent); + } + + @Override + public String getPropertyName() { + return Methods.propertyName(getTarget()); + } + + @Override + public Object getValue(Object parent) throws Exception { + final boolean mustUnset = Reflection.setAccessible(getTarget(), true); + try { + return getTarget().invoke(parent); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException(e); + } finally { + if (mustUnset) { + Reflection.setAccessible(getTarget(), false); + } + } + } + } + + protected PropertyD(MetadataReader.ForContainer<E> reader, BeanD<?> parent) { + super(reader, parent); + } + + public final Stream<GraphContext> read(GraphContext context) { + Validate.notNull(context); + if (context.getValue() == null) { + return Stream.empty(); + } + try { + final Object value = getValue(context.getValue()); + final PathImpl p = context.getPath(); + p.addProperty(getPropertyName()); + return Stream.of(context.child(p, value)); + } catch (Exception e) { + throw e instanceof ValidationException ? (ValidationException) e : new ValidationException(e); + } + } + + public abstract Object getValue(Object parent) throws Exception; +}