François,

Your test is incorrect. Even your CustomGrantedAuthority shows the problem. Your equals() method only checks on the authority property. I have a custom GrantedAuthority object which not only looks at the authority property for equality but another property as well. As a result, my hashCode() method was different as well because it took into account this other property.

In the tag's code you use methods of the Set interface: retainAll and containsAll. Both of those methods are going to use the equals and hashCode methods of my custom GA which is different than the equals and hashCode of the GAImpl class.

For example:

Code:
public boolean equals(Object obj) {
        if (!(obj instanceof CustomGrantedAuthority))  
            return false; <-- this will be hit when comparing the GAImpl to the Custom one here &#40;you make an assumption that the only thing that should be used for comparison is whatever is in the GA interface.&#41; 

        CustomGrantedAuthority role = &#40;CustomGrantedAuthority&#41; obj;
        return new EqualsBuilder&#40;&#41;.append&#40;role.getAuthority&#40;&#41;, this.getAuthority&#40;&#41;&#41;.append&#40;role.getCode&#40;&#41;, this.getCode&#40;&#41;&#41;.isEquals&#40;&#41;;
    &#125;

    /**
     * @return
     */
    public int hashCode&#40;&#41; &#123;
        return new HashCodeBuilder&#40;13,23&#41;.append&#40;this.authority&#41;.append&#40;this.code&#41;.toHashCode&#40;&#41;
    &#125;
So, essentially what it boils down to is that by using the Set methods you are forcing the user to check only the authority property when creating the equals and hashCode methods. The fix is to get rid of the use of retainAll and containsAll and use a loop instead and pulling out and comparing the authority properties directly (or you can use CollectionUtils in Jakarta-Collections (though I don't remember if you had that dependency already or not)).

Here is one of the problem areas in the code (lines 150-56):

Code:
private Set retainAll&#40;final Collection granted,
                          final Set requiredAuthorities&#41; &#123;
        Set grantedCopy = new HashSet&#40;granted&#41;; <-- granted is a collection of CustomGA
        grantedCopy.retainAll&#40;requiredAuthorities&#41;; <-- requiredAuthorities is  a set of GAImpl, which you build on lines 137-148&#41;.  This is where the disconnect is and as a result, nothing will be retained because the requiredAuthority never equals a CustomGA

        return grantedCopy;
    &#125;
And the other problem area (lines 96-101):

Code:
if &#40;&#40;null != evaledIfAllGranted&#41; && !"".equals&#40;evaledIfAllGranted&#41;&#41; &#123;
            if &#40;!granted.containsAll&#40; <-- granted is a collection of CustomGA, but you are asking if it contains all of the GAImpls.
                    parseAuthoritiesString&#40;evaledIfAllGranted&#41;&#41;&#41; &#123;
                return Tag.SKIP_BODY;
            &#125;
        &#125;
Hope this helps,

Rexxe