Fixed
Details
Assignee
Guillaume SmetGuillaume SmetReporter
tp123tp123Labels
Bug Testcase Reminder (view)
Bug reports should generally be accompanied by a test case!
Bug Testcase Reminder (edit)
Bug reports should generally be accompanied by a test case!
Feedback Requested
Jan 03, 2019Participants
Guillaume SmetGunnar Morlingleedongtp123Components
Fix versions
Affects versions
Priority
Blocker
Details
Details
Assignee
Guillaume Smet
Guillaume SmetReporter
tp123
tp123Labels
Bug Testcase Reminder (view)
Bug reports should generally be accompanied by a test case!
Bug Testcase Reminder (edit)
Bug reports should generally be accompanied by a test case!
Feedback Requested
Jan 03, 2019
Participants
Guillaume Smet
Gunnar Morling
leedong
tp123
Components
Fix versions
Affects versions
Priority
Created January 3, 2019 at 12:42 PM
Updated January 7, 2019 at 3:57 PM
Resolved January 4, 2019 at 1:29 PM
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; }