<style>
/* Changing the layout to use less space for mobiles */
@media screen and (max-device-width: 480px), screen and (-webkit-min-device-pixel-ratio: 2) {
    #email-body { min-width: 30em !important; }
    #email-page { padding: 8px !important; }
    #email-banner { padding: 8px 8px 0 8px !important; }
    #email-avatar { margin: 1px 8px 8px 0 !important; padding: 0 !important; }
    #email-fields { padding: 0 8px 8px 8px !important; }
    #email-gutter { width: 0 !important; }
}
</style>
<div id="email-body">
<table id="email-wrap" align="center" border="0" cellpadding="0" cellspacing="0" style="background-color:#f0f0f0;color:#000000;width:100%;">
    <tr valign="top">
        <td id="email-page" style="padding:16px !important;">
            <table align="center" border="0" cellpadding="0" cellspacing="0" style="background-color:#ffffff;border:1px solid #bbbbbb;color:#000000;width:100%;">
                <tr valign="top">
                    <td bgcolor="#3e4c4e" style="background-color:#3e4c4e;color:#ffffff;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:12px;line-height:1;"><img src="https://www.jboss.org/dms/hibernate/images/jira/jiraheader_hibernate.png" alt="" style="vertical-align:top;" /></td>
                </tr><tr valign="top">
    <td id="email-banner" style="padding:32px 32px 0 32px;">

                
        
        
            <table align="left" border="0" cellpadding="0" cellspacing="0" width="100%" style="width:100%;">
    <tr valign="top">
        <td style="color:#505050;font-family:Arial,FreeSans,Helvetica,sans-serif;padding:0;">
                                        <img id="email-avatar" src="https://hibernate.onjira.com/secure/useravatar?ownerId=gunnar.morling&avatarId=10345" alt="" height="48" width="48" border="0" align="left" style="padding:0;margin: 0 16px 16px 0;" />
                        <div id="email-action" style="padding: 0 0 8px 0;font-size:12px;line-height:18px;">
                                    <a class="user-hover" rel="gunnar.morling" id="email_gunnar.morling" href="https://hibernate.onjira.com/secure/ViewProfile.jspa?name=gunnar.morling" style="color:#6c797f;">Gunnar Morling</a>
     updated <img src="https://hibernate.onjira.com/images/icons/bug.gif" height="16" width="16" border="0" align="absmiddle" alt="Bug"> <a style='color:#6c797f;text-decoration:none;' href='https://hibernate.onjira.com/browse/HV-662'>HV-662</a>
            </div>
                        <div id="email-summary" style="font-size:16px;line-height:20px;padding:2px 0 16px 0;">
                <a style='color:#6c797f;text-decoration:none;' href='https://hibernate.onjira.com/browse/HV-662'><strong>ConstraintValidatorManager caching fails for XML-defined constraints</strong></a>
            </div>
                    </td>
    </tr>
</table>
        
    </td>
</tr>
<tr valign="top">
    <td id="email-fields" style="padding:0 32px 32px 32px;">
        <table border="0" cellpadding="0" cellspacing="0" style="padding:0;text-align:left;width:100%;" width="100%">
            <tr valign="top">
                <td id="email-gutter" style="width:64px;white-space:nowrap;"></td>
                <td>
                    <table border="0" cellpadding="0" cellspacing="0" width="100%">
                                                    <tr valign="top">
        <td style="color:#000000;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:12px;padding:0 10px 10px 0;white-space:nowrap;">
            <strong style="font-weight:normal;color:#505050;">Change By:</strong>
        </td>
        <td style="color:#000000;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:12px;padding:0 0 10px 0;width:100%;">
                                                <a class="user-hover" rel="gunnar.morling" id="email_gunnar.morling" href="https://hibernate.onjira.com/secure/ViewProfile.jspa?name=gunnar.morling" style="color:#6c797f;">Gunnar Morling</a>
                            (17/Dec/12 2:18 PM)
        </td>
    </tr>
            <tr valign="top">
        <td style="color:#000000;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:12px;padding:0 10px 10px 0;white-space:nowrap;">
            <strong style="font-weight:normal;color:#505050;">Description:</strong>
        </td>
        <td style="color:#000000;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:12px;padding:0 0 10px 0;width:100%;">
                                    <span class="diffcontext">Heap&nbsp;analysis&nbsp;of&nbsp;my&nbsp;webapp&nbsp;showed&nbsp;that&nbsp;I&nbsp;have&nbsp;several&nbsp;thousand&nbsp;live&nbsp;instances&nbsp;of&nbsp;ConstraintValidatorManager$CacheKey,&nbsp;with&nbsp;the&nbsp;numbers&nbsp;growing&nbsp;with&nbsp;every&nbsp;subsequent&nbsp;request.&nbsp;This&nbsp;was&nbsp;surprising&nbsp;given&nbsp;that&nbsp;the&nbsp;application&nbsp;had&nbsp;only&nbsp;3&nbsp;constraints&nbsp;configured&nbsp;(via&nbsp;XML).<br><br>Hooking&nbsp;up&nbsp;the&nbsp;debugger,&nbsp;I&nbsp;could&nbsp;see&nbsp;that&nbsp;the&nbsp;cache&nbsp;lookup&nbsp;on&nbsp;line&nbsp;92&nbsp;of&nbsp;ConstraintValidatorManager&nbsp;always&nbsp;fails&nbsp;-&nbsp;even&nbsp;though&nbsp;the&nbsp;validator&nbsp;is&nbsp;already&nbsp;cached,&nbsp;a&nbsp;new&nbsp;instance&nbsp;is&nbsp;initialized&nbsp;and&nbsp;returned.<br><br>{code:title=ConstraintValidatorManager.java|borderStyle=solid}<br>ConstraintValidator&lt;A,&nbsp;V&gt;&nbsp;constraintValidator&nbsp;=&nbsp;(ConstraintValidator&lt;A,&nbsp;V&gt;)&nbsp;constraintValidatorCache.get(&nbsp;key&nbsp;);<br>{code}<br><br>I&nbsp;set&nbsp;a&nbsp;breakpoint&nbsp;on&nbsp;the&nbsp;equals&nbsp;method&nbsp;of&nbsp;CacheKey,&nbsp;and&nbsp;found&nbsp;that&nbsp;it&nbsp;always&nbsp;returns&nbsp;false&nbsp;when&nbsp;comparing&nbsp;the&nbsp;annotation&nbsp;member&nbsp;of&nbsp;the&nbsp;two&nbsp;CacheKeys&nbsp;-&nbsp;even&nbsp;when&nbsp;both&nbsp;annotations&nbsp;refer&nbsp;to&nbsp;the&nbsp;same&nbsp;instance.<br>{code:title=ConstraintValidatorManager$CacheKey.java|borderStyle=solid}<br>if&nbsp;(&nbsp;annotation&nbsp;!=&nbsp;null&nbsp;?&nbsp;!annotation.equals(&nbsp;cacheKey.annotation&nbsp;)&nbsp;:&nbsp;cacheKey.annotation&nbsp;!=&nbsp;null&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;<br>}<br>{code}<br><br>The&nbsp;annotation&nbsp;in&nbsp;this&nbsp;case&nbsp;isn&#39;t&nbsp;a&nbsp;real&nbsp;annotation&nbsp;(because&nbsp;the&nbsp;constraints&nbsp;are&nbsp;defined&nbsp;in&nbsp;XML)&nbsp;-&nbsp;it&#39;s&nbsp;a&nbsp;JDK&nbsp;dynamic&nbsp;Proxy&nbsp;which&nbsp;uses&nbsp;the&nbsp;*AnnotationProxy*&nbsp;class&nbsp;as&nbsp;its&nbsp;InvocationHandler.<br>{code:title=AnnotationProxy.java|borderStyle=solid}<br>public&nbsp;Object&nbsp;invoke(Object&nbsp;proxy,&nbsp;Method&nbsp;method,&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Throwable&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;values.containsKey(&nbsp;method.getName()&nbsp;)&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;values.get(&nbsp;method.getName()&nbsp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;method.invoke(&nbsp;this,&nbsp;args&nbsp;);<br>}<br></span>
<span class="diffaddedchars" style="background-color:#ddfade;">{code}<br><br></span>
<span class="diffcontext">When&nbsp;equals()&nbsp;is&nbsp;called&nbsp;via&nbsp;the&nbsp;dynamic&nbsp;Proxy,&nbsp;the&nbsp;eventual&nbsp;invocation&nbsp;is&nbsp;a&nbsp;call&nbsp;to&nbsp;Object.equals().&nbsp;The&nbsp;problem&nbsp;is&nbsp;that&nbsp;the&nbsp;left-hand&nbsp;argument&nbsp;is&nbsp;*this*&nbsp;-&nbsp;an&nbsp;AnnotationProxy&nbsp;instance,&nbsp;and&nbsp;the&nbsp;right-hand&nbsp;argument&nbsp;is&nbsp;a&nbsp;dynamic&nbsp;Proxy&nbsp;instance.&nbsp;Object.equals()&nbsp;therefore&nbsp;always&nbsp;returns&nbsp;false.<br><br>This&nbsp;simple&nbsp;piece&nbsp;of&nbsp;code&nbsp;shows&nbsp;the&nbsp;broken&nbsp;call&nbsp;to&nbsp;equals()&nbsp;clearly.<br><br>{code:title=Test.java|borderStyle=solid}<br>AnnotationDescriptor&lt;DecimalMin&gt;&nbsp;descriptor&nbsp;=&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;AnnotationDescriptor&lt;DecimalMin&gt;(DecimalMin.class);<br>descriptor.setValue(&quot;message&quot;,&nbsp;&quot;some&nbsp;message&quot;);<br>descriptor.setValue(&quot;value&quot;,&nbsp;&quot;1&quot;);<br>                <br>AnnotationProxy&nbsp;proxy&nbsp;=&nbsp;new&nbsp;AnnotationProxy(descriptor);<br>        <br>Annotation&nbsp;annotation&nbsp;=&nbsp;(Annotation)Proxy.newProxyInstance(<br>&nbsp;&nbsp;&nbsp;&nbsp;DecimalMin.class.getClassLoader(),<br>&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;Class[]&nbsp;{&nbsp;DecimalMin.class&nbsp;},<br>&nbsp;&nbsp;&nbsp;&nbsp;proxy);<br><br>System.out.println(annotation.equals(annotation));<br>{code}<br>The&nbsp;call&nbsp;annotation.equals(annotation)&nbsp;always&nbsp;returns&nbsp;false.</span>

        </td>
    </tr>
                            </table>
                </td>
            </tr>
        </table>
    </td>
</tr>













            </table>
        </td><!-- End #email-page -->
    </tr>
    <tr valign="top">
        <td style="color:#505050;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:10px;line-height:14px;padding: 0 16px 16px 16px;text-align:center;">
            This message is automatically generated by JIRA.<br />
            If you think it was sent incorrectly, please contact your JIRA administrators<br />
            For more information on JIRA, see: <a style='color:#6c797f;' href='http://www.atlassian.com/software/jira'>http://www.atlassian.com/software/jira</a>
        </td>
    </tr>
</table><!-- End #email-wrap -->
</div><!-- End #email-body -->