Uploaded image for project: 'Weld'
  1. Weld
  2. WELD-2185

ArraySet.hashCode() breaks java.util.Set.hashCode() contract

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • Major
    • 2.3.5.Final
    • 1.1.33.Final, 2.3.4.Final
    • None
    • None
    • Hide

      This code stores discovered Bean s in a Map Map<Set<Annotation>, Bean> and performs later a lookup by constructing a HashSet containing the matching annotations.

      Show
      This code stores discovered Bean s in a Map Map<Set<Annotation>, Bean> and performs later a lookup by constructing a HashSet containing the matching annotations.

    Description

      Weld uses ArraySet to store qualifiers in a Bean. Extensions that store qualifiers to a Bean and reguster custom Bean instances based on ProcessAnnotatedType with qualifiers are no longer able to use simple matching to obtain the Bean by its qualifiers.

      Exceprt:

      	Map<Set<Annotation>, Bean<CouchbaseOperations>> couchbaseOperationsMap = new HashMap<Set<Annotation>, Bean<CouchbaseOperations>>();
      
      	<T> void processBean(@Observes ProcessBean<T> processBean) {
      		Bean<T> bean = processBean.getBean();
      		couchbaseOperationsMap.put(bean.getQualifiers(), ((Bean<CouchbaseOperations>) bean));
      	}
      	 // later ...
      	
      	void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
      		
      		Bean<CouchbaseOperations> couchbaseOperationsBean = this.couchbaseOperationsMap.get(new HashSet<>(Arrays.asList(Default.class, Any.class)));
      		// couchbaseOperationsBean is null
      	}
      	
      

      This code stores discovered Bean s in a Map Map<Set<Annotation>, Bean> and performs later a lookup by constructing a HashSet containing the matching annotations.

      Example with more context:

      	private final Map<Set<Annotation>, Bean<CouchbaseOperations>> couchbaseOperationsMap = new HashMap<Set<Annotation>, Bean<CouchbaseOperations>>();
      
      	<T> void processBean(@Observes ProcessBean<T> processBean) {
      		Bean<T> bean = processBean.getBean();
      		for (Type type : bean.getTypes()) {
      			if (type instanceof Class<?> && CouchbaseOperations.class.isAssignableFrom((Class<?>) type)) {
      				couchbaseOperationsMap.put(bean.getQualifiers(), ((Bean<CouchbaseOperations>) bean));
      			}
      		}
      	}
      
      	protected <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> processAnnotatedType) {
      
      		AnnotatedType<X> annotatedType = processAnnotatedType.getAnnotatedType();
      		Class<X> repositoryType = annotatedType.getJavaClass();
      
      		if (isRepository(repositoryType)) {
      
      			Set<Annotation> qualifiers = getQualifiers(repositoryType);
      
      			// Store the repository type using its qualifiers.
      			repositoryTypes.put(repositoryType, qualifiers);
      		}
      	}
      
      	void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
      		for (Map.Entry<Class<?>, Set<Annotation>> entry : getRepositoryTypes()) {
      			Class<?> repositoryType = entry.getKey();
      			Set<Annotation> qualifiers = entry.getValue();
      			Bean<CouchbaseOperations> couchbaseOperationsBean = this.couchbaseOperationsMap.get(qualifiers);
      			
      			// couchbaseOperationsBean is null
      		}
      	}
      	
      	/**
      	 * Determines the qualifiers of the given type.
      	 */
      	private Set<Annotation> getQualifiers(final Class<?> type) {
      
      		Set<Annotation> qualifiers = new HashSet<Annotation>();
      		Annotation[] annotations = type.getAnnotations();
      		for (Annotation annotation : annotations) {
      			Class<? extends Annotation> annotationType = annotation.annotationType();
      			if (annotationType.isAnnotationPresent(Qualifier.class)) {
      				qualifiers.add(annotation);
      			}
      		}
      
      		// Add @Default qualifier if no qualifier is specified.
      		if (qualifiers.isEmpty()) {
      			qualifiers.add(DefaultAnnotationLiteral.INSTANCE);
      		}
      
      		// Add @Any qualifier.
      		qualifiers.add(AnyAnnotationLiteral.INSTANCE);
      		return qualifiers;
      	}
      

      References:

      Attachments

        Issue Links

          Activity

            People

              mkouba@redhat.com Martin Kouba
              mpaluch@paluch.biz Mark Paluch (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: