Uploaded image for project: 'Hibernate Validator'
  1. HV-1684

StackOverflowError with Hibernate Validator 6.0.13.Final

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Blocker
    • Resolution: Fixed
    • Affects Version/s: 6.0.13.Final
    • Fix Version/s: 6.1.0.Alpha3, 6.0.14.Final
    • Component/s: validators
    • Labels:
    • Environment:
      The environment is :x86_64 GNU/Linux JRE: 1.8.0_181 hibernate-validator:6.0.13Final

      Description

      when the process working for two days,StackOverflowError always happen,the stacktrace is below:

      java.lang.StackOverflowError
              at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
              at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
      	......
      	at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
              at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
              at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
              at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
              at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
              at java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1031)
              at org.hibernate.validator.internal.engine.valueextraction.ValueExtractorResolver.getRuntimeCompliantValueExtractors(ValueExtractorResolver.java:316)
              at org.hibernate.validator.internal.engine.valueextraction.ValueExtractorResolver.getValueExtractorCandidatesForContainerDetectionOfGlobalCascadedValidation(ValueExtractorResolver.java:177)
              at org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder.build(CascadingMetaDataBuilder.java:227)
              at org.hibernate.validator.internal.metadata.aggregated.FieldCascadable$Builder.build(FieldCascadable.java:83)
              at org.hibernate.validator.internal.metadata.aggregated.FieldCascadable$Builder.build(FieldCascadable.java:64)
              at org.hibernate.validator.internal.metadata.aggregated.PropertyMetaData$Builder.lambda$build$1(PropertyMetaData.java:347)
              at org.hibernate.validator.internal.metadata.aggregated.PropertyMetaData$Builder$$Lambda$62/1651906449.apply(Unknown Source)
              at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
              at java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1625)
              at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
              at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
              at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
              at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
              at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
              at org.hibernate.validator.internal.metadata.aggregated.PropertyMetaData$Builder.build(PropertyMetaData.java:348)
              at org.hibernate.validator.internal.metadata.aggregated.PropertyMetaData$Builder.build(PropertyMetaData.java:151)
              at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl$BuilderDelegate.build(BeanMetaDataImpl.java:784)
              at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl$BeanMetaDataBuilder.build(BeanMetaDataImpl.java:648)
              at org.hibernate.validator.internal.metadata.BeanMetaDataManager.createBeanMetaData(BeanMetaDataManager.java:192)
              at org.hibernate.validator.internal.metadata.BeanMetaDataManager.lambda$getBeanMetaData$0(BeanMetaDataManager.java:160)
              at org.hibernate.validator.internal.metadata.BeanMetaDataManager$$Lambda$53/253243426.apply(Unknown Source)
              at java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:324)
              at org.hibernate.validator.internal.metadata.BeanMetaDataManager.getBeanMetaData(BeanMetaDataManager.java:159)
              at org.hibernate.validator.internal.engine.ValidationContext$ValidationContextBuilder.forValidate(ValidationContext.java:566)
              at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:155)
      		at com.test.ValidateParameters.validateObject(ValidateParameters.java:31)
      

      The environment is :x86_64 GNU/Linux JRE: 1.8.0_181 hibernate-validator:6.0.13Final
      And our code is easy,just like this,first get validator in a static block,and then validate paramter for every request param:

      //get validator
      Validator  validator = Validation.byDefaultProvider()
      .providerResolver(new OsgiValidationProviderResolver())
      .configure().messageInterpolator(resouce)
      .buildValidatorFactory().getValidator();
      //validate parameter,this parameter is an Object,(we think it contains map attribute may have the problem).
      Set<ConstraintViolation> validateResultSets = validator.validate(parameter);
      

      Our team have view the code,we doubt the following code(ValueExtractorResolver.java, getRuntimeCompliantValueExtractors) may has some problem in Multithreading,why it always happens for a long time?
      When in thread one,the attribute "valueExtractorDescriptors" is not empty ,and it's type is java.util.map,then it will change to ImmutableSet,then a second thread run "valueExtractorDescriptors.isEmpty()",it will goes to the UnmodifiableCollection.isEmpty,this will recursion,at last it will throw SO Exception.

      private Set<ValueExtractorDescriptor> getRuntimeCompliantValueExtractors(Class<?> runtimeType, Set<ValueExtractorDescriptor> potentialValueExtractorDescriptors) {
      		if ( nonContainerTypes.contains( runtimeType ) ) {
      			return Collections.emptySet();
      		}
      		
      		Set<ValueExtractorDescriptor> valueExtractorDescriptors = possibleValueExtractorsByRuntimeType.get( runtimeType );
      		if ( valueExtractorDescriptors == null ) {
      			//otherwise we just look for maximally specific extractors for the runtime type
      			Set<ValueExtractorDescriptor> possibleValueExtractors = potentialValueExtractorDescriptors
      					.stream()
      					.filter( e -> TypeHelper.isAssignable( e.getContainerType(), runtimeType ) )
      					.collect( Collectors.toSet() );
      
      			valueExtractorDescriptors = getMaximallySpecificValueExtractors( possibleValueExtractors );
      		}
      
      		if ( valueExtractorDescriptors.isEmpty() ) {
      			nonContainerTypes.put( runtimeType, NON_CONTAINER_VALUE );
      		}
      		else {
      			Set<ValueExtractorDescriptor> extractorDescriptorsToCache = CollectionHelper.toImmutableSet( valueExtractorDescriptors );
      			possibleValueExtractorsByRuntimeType.put( runtimeType, extractorDescriptorsToCache );
      			return extractorDescriptorsToCache;
      		}
      
      		return valueExtractorDescriptors;
      	}
      

        Attachments

          Activity

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Feedback Requested: