5

We use the hibernate validator and dynamically class-loading in our project (by load class into a separate class-loader). After we realise that the class is not required we remove all references to the class and class-loader, then GC collects this.

What we get: Some time after the application starts the java reflection stops working.

java.lang.reflect.UndeclaredThrowableException: null
    at com.sun.proxy.$Proxy253.equals(Unknown Source)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager$CacheKey.equals(ConstraintValidatorManager.java:287)
    at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:940)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.getInitializedValidator(ConstraintValidatorManager.java:104)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorNoUnwrapping(ConstraintTree.java:301)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getConstraintValidatorInstanceForAutomaticUnwrapping(ConstraintTree.java:242)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.getInitializedConstraintValidator(ConstraintTree.java:163)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:116)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateComposingConstraints(ConstraintTree.java:396)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:98)
    at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:87)
    at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:73)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:616)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:581)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:527)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:495)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:460)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:410)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:207)
    at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:281)
    ... Many spring filters calls ...
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:122)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at *someAwesomePackage*.microservice.rest.spring.webapp.CabinetRequestFilter.doFilterInternal(CabinetRequestFilter.java:98)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.reflect.InvocationTargetException: null
    at sun.reflect.GeneratedMethodAccessor268.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.hibernate.validator.internal.util.annotationfactory.AnnotationProxy.invoke(AnnotationProxy.java:69)
    ... 260 common frames omitted
Caused by: java.lang.NullPointerException: null
    at org.hibernate.validator.internal.util.annotationfactory.AnnotationProxy.getAnnotationMemberValue(AnnotationProxy.java:248)
    at org.hibernate.validator.internal.util.annotationfactory.AnnotationProxy.equals(AnnotationProxy.java:104)
    ... 264 common frames omitted

Error happens in this place (method from java.lang.Class.java):

 private static Method searchMethods(Method[] methods,
                                    String name,
                                    Class<?>[] parameterTypes) {
    Method res = null;
    String internedName = name.intern();
    for (int i = 0; i < methods.length; i++) {
        Method m = methods[i];
        if (m.getName() == internedName
            && arrayContentsEq(parameterTypes, m.getParameterTypes())
            && (res == null
                || res.getReturnType().isAssignableFrom(m.getReturnType())))
            res = m;
    }
    return (res == null ? res : getReflectionFactory().copyMethod(res));
}

Class has method, but the comparison of m.getName () == internedName is false. Comparison returns false because names of the methods are not interned.

If I calling m.getName (). Intern () == internedName from debug, it returns true. But the method 'searchMethods' is from 'java.lang.Class'.

This always happens after some time from the application start.

Did anybody encounter such a problem?

EDIT (25/12/2017):

Not only hibernate validator failed, xml parsing failed too!

XML example:

<SELFCARE>
    <SESSION_ID>***</SESSION_ID>
</SELFCARE>

Mapping example:

@XmlRootElement(name = "SELFCARE")
@XmlAccessorType(XmlAccessType.FIELD)
public class Session {

    @XmlElement(name = "SESSION_ID")
    private String sessionId;
}

Parsing exception:

WARN  2017.12.25 20:00:05.991 +0300 org.apache.cxf.jaxrs.provider.AbstractJAXBProvider             javax.xml.bind.UnmarshalException
- with linked exception:
[com.sun.istack.SAXParseException2; lineNumber: 1; columnNumber: 1; unexpected element (uri:"", local:"SELFCARE"). Expected elements are <{}SELFCARE>]
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:483)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:417)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:386)
    at org.apache.cxf.jaxrs.provider.JAXBElementProvider.unmarshalFromInputStream(JAXBElementProvider.java:294)
    at org.apache.cxf.jaxrs.provider.JAXBElementProvider.doUnmarshal(JAXBElementProvider.java:245)

But mapping is correct and working, if reflection is working...

Alexey
  • 412
  • 3
  • 17
  • Did you try m.getName().intern() == internedName ? From documentation : When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true. – Kaushal Dec 20 '17 at 11:26
  • Does your class loader defer/delegate loading to parent class loader? – diginoise Dec 20 '17 at 11:32
  • Why not using equals instead of `==`. Can you mark the line with the NullpointerException, from my point of View the string interning will not lead to this – CoronA Dec 20 '17 at 11:39
  • @Kaushal yep, i try to call m.getName().intern() == internedName in debug - it returns true. – Alexey Dec 20 '17 at 12:06
  • Might it be the case that the trouble is happening due the multithreading? https://justavo.wordpress.com/2004/09/18/stringintern-and-synchronization/ – Ruslan Dec 20 '17 at 12:42

1 Answers1

1

From the stacktrace, I suspect you're using HV 5.x. Am I right?

The issue seems to be related to the fact that you have a proxy. I think it's probably related to the annotation being part of the key.

Could you try HV 6.0.7.Final? We got rid of using the annotation in the cache key here so it might solve your issue.

Be careful, we changed the groupId: it's now org.hibernate.validator (instead of org.hibernate) - be careful if the HV dependency is coming transitively from another artifact, add exclusions if need be.

You also need the javax.el dependency:

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.el</artifactId>
   <version>3.0.1-b08</version>
</dependency>

(be careful, there might be other javax.el artifacts in your dependencies so be sure to have only this one - the dependency hierarchy view of Eclipse might help)

You also need validation-api 2.0.1.Final (it comes transitively with HV but you might have to change the version if you explicitly declared it).

Other than that, you shouldn't have any compatibility issue (except if you were using experimental features such as value handling): it's a drop in replacement. HV 6 is also significantly faster so it should be a win-win situation.

Feel free to report any issue with your upgrade here, I'll help.

Guillaume Smet
  • 9,921
  • 22
  • 29
  • Guillaume Smet, thanks, it's working. But app are failing all the same. @aleksey-shipilev pls help! – Alexey Dec 25 '17 at 17:17