tioback / quarkus-mock-and-validate

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mockito and Validation interference

This project is an attempt to demonstrate how the use of Mockito's InjectMock and InjectSpy is affecting the correct behavior of Java Bean Validation.


From what I could tell, when either InjectMock or InjectSpy are used, the generated subclasses are called in an order that affects the Validation behaviour.

More specifically, at validateParameters(T, java.lang.reflect.Executable, java.lang.Object[], java.lang.Class<?>...):

// Dependency: hibernate-validator-6.2.0.Final.jar
package org.hibernate.validator.internal.engine;

public class ValidatorImpl {

    private <T> Set<ConstraintViolation<T>> validateParameters(T object, Executable executable, Object[] parameterValues, Class<?>... groups) {
        sanityCheckGroups(groups);

        @SuppressWarnings("unchecked")
        Class<T> rootBeanClass = object != null ? (Class<T>) object.getClass() : (Class<T>) executable.getDeclaringClass();
        BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData(rootBeanClass);

        if (!rootBeanMetaData.hasConstraints()) {
            return Collections.emptySet();
        }

        ExecutableValidationContext<T> validationContext = getValidationContextBuilder().forValidateParameters(
                rootBeanClass,
                rootBeanMetaData,
                object,
                executable,
                parameterValues
        );

        ValidationOrder validationOrder = determineGroupValidationOrder(groups);

        validateParametersInContext(validationContext, parameterValues, validationOrder);

        return validationContext.getFailingConstraints();
    }
}

At the rootBeanMetaData.hasConstraints() check, when using Spies or Mocks, the variable is false.

After some debugging, I noticed that this happens because Spies and Mocks cause the use of org.hibernate.validator.internal.metadata.PredefinedScopeBeanMetaDataManager.UninitializedBeanMetaData.hasConstraints as the BeanMetadData implementation. Which in turn led me to this:

// Dependency: hibernate-validator-6.2.0.Final.jar
package org.hibernate.validator.internal.metadata;

public class PredefinedScopeBeanMetaDataManager implements BeanMetaDataManager {
    
    @Override
    public <T> BeanMetaData<T> getBeanMetaData(Class<T> beanClass) {
        Class<?> normalizedBeanClass = beanMetaDataClassNormalizer.normalize( beanClass );
        BeanMetaData<T> beanMetaData = (BeanMetaData<T>) beanMetaDataMap.get( normalizedBeanClass );
        if ( beanMetaData == null ) {
            // note that if at least one element of the hierarchy is constrained, the child classes should really be initialized
            // otherwise they will be considered unconstrained.
            beanMetaData = (BeanMetaData<T>) beanMetaDataMap.computeIfAbsent( normalizedBeanClass, UninitializedBeanMetaData::new );
        }
        return beanMetaData;
    }
}

That comment about child classes seems to be the reason this is happening.

Before I start working on a solution, I was wondering if someone has a word on that.

About


Languages

Language:Java 62.9%Language:HTML 37.1%