Created
January 21, 2013 11:27
-
-
Save rmannibucau/4585407 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Index: webbeans-impl/src/main/java/org/apache/webbeans/container/BeanManagerImpl.java | |
| =================================================================== | |
| --- webbeans-impl/src/main/java/org/apache/webbeans/container/BeanManagerImpl.java (revision 1436220) | |
| +++ webbeans-impl/src/main/java/org/apache/webbeans/container/BeanManagerImpl.java (working copy) | |
| @@ -91,6 +91,8 @@ | |
| import org.apache.webbeans.util.WebBeansUtil; | |
| import org.apache.webbeans.xml.WebBeansXMLConfigurator; | |
| +import static org.apache.webbeans.util.InjectionExceptionUtil.throwAmbiguousResolutionException; | |
| + | |
| /** | |
| * Implementation of the {@link BeanManager} contract of the web beans | |
| * container. | |
| Index: webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java | |
| =================================================================== | |
| --- webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java (revision 1436220) | |
| +++ webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java (working copy) | |
| @@ -18,48 +18,22 @@ | |
| */ | |
| package org.apache.webbeans.container; | |
| -import org.apache.webbeans.util.AnnotationUtil; | |
| +import org.apache.webbeans.inject.instance.InstanceCacheKey; | |
| -import javax.enterprise.util.Nonbinding; | |
| import java.lang.annotation.Annotation; | |
| -import java.lang.reflect.Array; | |
| -import java.lang.reflect.Method; | |
| import java.lang.reflect.Type; | |
| -import java.util.Arrays; | |
| -import java.util.Comparator; | |
| -public final class BeanCacheKey | |
| +public final class BeanCacheKey extends InstanceCacheKey | |
| { | |
| private final Type type; | |
| private final String path; | |
| - private final Annotation qualifier; | |
| - private final Annotation qualifiers[]; | |
| private final int hashCode; | |
| - private static final Comparator<Annotation> ANNOTATION_COMPARATOR = new AnnotationComparator(); | |
| public BeanCacheKey( Type type, String path, Annotation... qualifiers ) | |
| { | |
| + super(qualifiers); | |
| this.type = type; | |
| this.path = path; | |
| - final int length = qualifiers != null ? qualifiers.length : 0; | |
| - if (length == 0) | |
| - { | |
| - this.qualifier = null; | |
| - this.qualifiers = null; | |
| - } | |
| - else if (length == 1) | |
| - { | |
| - this.qualifier = qualifiers[0]; | |
| - this.qualifiers = null; | |
| - } | |
| - else | |
| - { | |
| - this.qualifier = null; | |
| - // to save array creations, we only create an array, if we have more than one annotation | |
| - this.qualifiers = new Annotation[length]; | |
| - System.arraycopy(qualifiers, 0, this.qualifiers, 0, length); | |
| - Arrays.sort(this.qualifiers, ANNOTATION_COMPARATOR); | |
| - } | |
| // this class is directly used in ConcurrentHashMap.get() so simply init the hasCode here | |
| hashCode = computeHashCode(); | |
| @@ -83,14 +57,10 @@ | |
| { | |
| return false; | |
| } | |
| - if (qualifier != null ? !qualifierEquals(qualifier, cacheKey.qualifier) : cacheKey.qualifier != null) | |
| + if (!super.equals(cacheKey)) | |
| { | |
| return false; | |
| } | |
| - if (!qualifierArrayEquals(qualifiers, cacheKey.qualifiers)) | |
| - { | |
| - return false; | |
| - } | |
| if (path != null ? !path.equals(cacheKey.path) : cacheKey.path != null) | |
| { | |
| return false; | |
| @@ -99,33 +69,6 @@ | |
| return true; | |
| } | |
| - private boolean qualifierArrayEquals(Annotation[] qualifiers1, Annotation[] qualifiers2) | |
| - { | |
| - if (qualifiers1 == qualifiers2) | |
| - { | |
| - return true; | |
| - } | |
| - else if (qualifiers1 == null || qualifiers2 == null) | |
| - { | |
| - return false; | |
| - } | |
| - if (qualifiers1.length != qualifiers2.length) | |
| - { | |
| - return false; | |
| - } | |
| - for (int i = 0; i < qualifiers1.length; i++) | |
| - { | |
| - Annotation a1 = qualifiers1[i]; | |
| - Annotation a2 = qualifiers2[i]; | |
| - if (a1 == null ? a2 != null : !qualifierEquals(a1, a2)) | |
| - { | |
| - return false; | |
| - } | |
| - } | |
| - | |
| - return true; | |
| - } | |
| - | |
| @Override | |
| public int hashCode() | |
| { | |
| @@ -133,177 +76,19 @@ | |
| } | |
| /** | |
| - * We need this method as some weird JVMs return 0 as hashCode for classes. | |
| - * In that case we return the hashCode of the String. | |
| - */ | |
| - private int getTypeHashCode(Type type) | |
| - { | |
| - int typeHash = type.hashCode(); | |
| - if (typeHash == 0 && type instanceof Class) | |
| - { | |
| - return ((Class)type).getName().hashCode(); | |
| - // the type.toString() is always the same: "java.lang.Class@<hexid>" | |
| - // was: return type.toString().hashCode(); | |
| - } | |
| - | |
| - return typeHash; | |
| - } | |
| - | |
| - /** | |
| * Compute the HashCode. This should be called only in the constructor. | |
| */ | |
| private int computeHashCode() | |
| { | |
| int computedHashCode = 31 * getTypeHashCode(type) + (path != null ? path.hashCode() : 0); | |
| - if (qualifier != null) | |
| + if (hasQualifiers()) | |
| { | |
| - computedHashCode = 31 * computedHashCode + getQualifierHashCode(qualifier); | |
| + computedHashCode = 31 * computedHashCode + super.hashCode(); | |
| } | |
| - if (qualifiers != null) | |
| - { | |
| - for (int i = 0; i < qualifiers.length; i++) | |
| - { | |
| - computedHashCode = 31 * computedHashCode + getQualifierHashCode(qualifiers[i]); | |
| - } | |
| - } | |
| return computedHashCode; | |
| } | |
| /** | |
| - * Calculate the hashCode() of a qualifier, which ignores {@link Nonbinding} members. | |
| - */ | |
| - private int getQualifierHashCode(Annotation a) | |
| - { | |
| - Class annotationClass = getAnnotationClass(a.getClass()); | |
| - | |
| - if (annotationClass == null) | |
| - { | |
| - return getTypeHashCode(a.getClass()); | |
| - } | |
| - | |
| - // the hashCode of an Annotation is calculated solely via the hashCodes | |
| - // of it's members. If there are no members, it is 0. | |
| - // thus we first need to get the annotation-class hashCode | |
| - int hashCode = getTypeHashCode(annotationClass); | |
| - | |
| - // and now add the hashCode of all it's Nonbinding members | |
| - // the following algorithm is defined by the Annotation class definition | |
| - // see the JavaDoc for Annotation! | |
| - // we only change it so far that we skip evaluating @Nonbinding members | |
| - final Method[] members = annotationClass.getDeclaredMethods(); | |
| - | |
| - for (Method member : members) | |
| - { | |
| - if (member.isAnnotationPresent(Nonbinding.class)) | |
| - { | |
| - // ignore the non binding | |
| - continue; | |
| - } | |
| - | |
| - // Member value | |
| - final Object object = callMethod(a, member); | |
| - final int value; | |
| - if(object.getClass().isArray()) | |
| - { | |
| - Class<?> type = object.getClass().getComponentType(); | |
| - if(type.isPrimitive()) | |
| - { | |
| - if(Long.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((long[]) object); | |
| - } | |
| - else if(Integer.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((int[])object); | |
| - } | |
| - else if(Short.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((short[])object); | |
| - } | |
| - else if(Double.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((double[])object); | |
| - } | |
| - else if(Float.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((float[])object); | |
| - } | |
| - else if(Boolean.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((boolean[])object); | |
| - } | |
| - else if(Byte.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((byte[])object); | |
| - } | |
| - else if(Character.TYPE == type) | |
| - { | |
| - value = Arrays.hashCode((char[])object); | |
| - } | |
| - else | |
| - { | |
| - value = 0; | |
| - } | |
| - } | |
| - else | |
| - { | |
| - value = Arrays.hashCode((Object[])object); | |
| - } | |
| - } | |
| - else | |
| - { | |
| - value = object.hashCode(); | |
| - } | |
| - | |
| - hashCode = 29 * hashCode + value; | |
| - hashCode = 29 * hashCode + member.getName().hashCode(); | |
| - } | |
| - | |
| - return hashCode; | |
| - } | |
| - | |
| - /** | |
| - * Implements the equals() method for qualifiers, which ignores {@link Nonbinding} members. | |
| - */ | |
| - private boolean qualifierEquals(Annotation qualifier1, Annotation qualifier2) | |
| - { | |
| - return ANNOTATION_COMPARATOR.compare(qualifier1, qualifier2) == 0; | |
| - } | |
| - | |
| - private static Class getAnnotationClass(Class a) | |
| - { | |
| - for (Class i : a.getInterfaces()) | |
| - { | |
| - if (i.isAnnotation()) | |
| - { | |
| - return i; | |
| - } | |
| - } | |
| - return null; | |
| - } | |
| - | |
| - /** | |
| - * Helper method for calculating the hashCode of an annotation. | |
| - */ | |
| - private static Object callMethod(Object instance, Method method) | |
| - { | |
| - try | |
| - { | |
| - if (!method.isAccessible()) | |
| - { | |
| - method.setAccessible(true); | |
| - } | |
| - | |
| - return method.invoke(instance, AnnotationUtil.EMPTY_OBJECT_ARRAY); | |
| - } | |
| - catch (Exception e) | |
| - { | |
| - throw new RuntimeException("Exception in method call : " + method.getName(), e); | |
| - } | |
| - | |
| - } | |
| - | |
| - /** | |
| * for debugging ... | |
| */ | |
| @Override | |
| @@ -311,118 +96,6 @@ | |
| { | |
| return "BeanCacheKey{" + "type=" + type + ", path='" + path + '\'' | |
| + ", qualifiers=" | |
| - + (qualifiers == null ? qualifier : Arrays.asList(qualifiers)) + ", hashCode=" + hashCode + '}'; | |
| + + super.toString() + ", hashCode=" + hashCode + '}'; | |
| } | |
| - | |
| - /** | |
| - * to keep the annotations ordered. | |
| - */ | |
| - private static class AnnotationComparator implements Comparator<Annotation> | |
| - { | |
| - | |
| - // Notice: Sorting is a bit costly, but the use of this code is very rar. | |
| - public int compare(Annotation annotation1, Annotation annotation2) | |
| - { | |
| - final Class<? extends Annotation> type1 = annotation1.annotationType(); | |
| - final Class<? extends Annotation> type2 = annotation2.annotationType(); | |
| - final int temp = type1.getName().compareTo(type2.getName()); | |
| - if (temp != 0) | |
| - { | |
| - return temp; | |
| - } | |
| - final Method[] member1 = type1.getDeclaredMethods(); | |
| - final Method[] member2 = type2.getDeclaredMethods(); | |
| - | |
| - // TBD: the order of the list of members seems to be deterministic | |
| - | |
| - int i = 0; | |
| - int j = 0; | |
| - final int length1 = member1.length; | |
| - final int length2 = member2.length; | |
| - | |
| - // find next nonbinding | |
| - for (;; i++, j++) | |
| - { | |
| - while (i < length1 && member1[i].isAnnotationPresent(Nonbinding.class)) | |
| - { | |
| - i++; | |
| - } | |
| - while (j < length2 && member2[j].isAnnotationPresent(Nonbinding.class)) | |
| - { | |
| - j++; | |
| - } | |
| - if (i >= length1 && j >= length2) | |
| - { // both ended | |
| - return 0; | |
| - } | |
| - else if (i >= length1) | |
| - { // #1 ended | |
| - return 1; | |
| - } | |
| - else if (j >= length2) | |
| - { // #2 ended | |
| - return -1; | |
| - } | |
| - else | |
| - { // not ended | |
| - int c = member1[i].getName().compareTo(member2[j].getName()); | |
| - if (c != 0) | |
| - { | |
| - return c; | |
| - } | |
| - final Object value1 = callMethod(annotation1, member1[i]); | |
| - final Object value2 = callMethod(annotation2, member2[j]); | |
| - assert value1.getClass().equals(value2.getClass()); | |
| - | |
| - if (value1 instanceof Comparable) | |
| - { | |
| - c = ((Comparable)value1).compareTo(value2); | |
| - if (c != 0) | |
| - { | |
| - return c; | |
| - } | |
| - } | |
| - else if (value1.getClass().isArray()) | |
| - { | |
| - c = value1.getClass().getComponentType().getName() | |
| - .compareTo(value2.getClass().getComponentType().getName()); | |
| - if (c != 0) | |
| - { | |
| - return c; | |
| - } | |
| - | |
| - final int length = Array.getLength(value1); | |
| - c = length - Array.getLength(value2); | |
| - if (c != 0) | |
| - { | |
| - return c; | |
| - } | |
| - for (int k = 0; k < length; k++) | |
| - { | |
| - c = ((Comparable)Array.get(value1, k)).compareTo(Array.get(value2, k)); | |
| - if (c != 0) | |
| - { | |
| - return c; | |
| - } | |
| - } | |
| - | |
| - } | |
| - else if (value1 instanceof Class) | |
| - { | |
| - | |
| - c = ((Class)value1).getName().compareTo(((Class) value2).getName()); | |
| - if (c != 0) | |
| - { | |
| - return c; | |
| - } | |
| - } | |
| - else | |
| - { | |
| - // valid types for members are only Comparable, Arrays, or Class | |
| - assert false; | |
| - } | |
| - } | |
| - } | |
| - } | |
| - } | |
| } | |
| Index: webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java | |
| =================================================================== | |
| --- webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java (revision 1436220) | |
| +++ webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java (working copy) | |
| @@ -423,15 +423,12 @@ | |
| return beansXMLScanner.getBeansXml(injectionPointBeanClass); | |
| } | |
| - /** | |
| - * Resolution by type. | |
| - * | |
| - * @param injectionPointType injection point api type | |
| - * @param qualifiers qualifiers of the injection point | |
| - * @return set of resolved beans | |
| - */ | |
| public Set<Bean<?>> implResolveByType(Type injectionPointType, Class<?> injectinPointClass, Annotation... qualifiers) | |
| { | |
| + return implResolveByType(null, injectionPointType, injectinPointClass, qualifiers); | |
| + } | |
| + | |
| + public BeanCacheKey computeKey(Type injectionPointType, Class<?> injectinPointClass, Annotation... qualifiers) { | |
| ScannerService scannerService = webBeansContext.getScannerService(); | |
| String bdaBeansXMLFilePath = null; | |
| if (scannerService.isBDABeansXmlScanningEnabled()) | |
| @@ -448,6 +445,28 @@ | |
| bdaBeansXMLFilePath = getBDABeansXMLPath(injectinPointClass); | |
| } | |
| + return new BeanCacheKey(injectionPointType, bdaBeansXMLFilePath, qualifiers); | |
| + } | |
| + | |
| + /** | |
| + * Resolution by type. | |
| + * | |
| + * @param injectionPointType injection point api type | |
| + * @param qualifiers qualifiers of the injection point | |
| + * @return set of resolved beans | |
| + */ | |
| + public Set<Bean<?>> implResolveByType(BeanCacheKey cacheKey, Type injectionPointType, Class<?> injectinPointClass, Annotation... qualifiers) | |
| + { | |
| + if (cacheKey == null) { | |
| + cacheKey = computeKey(injectionPointType, injectinPointClass, qualifiers); | |
| + } | |
| + | |
| + Set<Bean<?>> resolvedComponents = resolvedBeansByType.get(cacheKey); | |
| + if (resolvedComponents != null) | |
| + { | |
| + return resolvedComponents; | |
| + } | |
| + | |
| boolean currentQualifier = false; | |
| if (isInstanceOrEventInjection(injectionPointType)) | |
| @@ -463,14 +482,6 @@ | |
| } | |
| } | |
| - BeanCacheKey cacheKey = new BeanCacheKey(injectionPointType, bdaBeansXMLFilePath, qualifiers); | |
| - | |
| - Set<Bean<?>> resolvedComponents = resolvedBeansByType.get(cacheKey); | |
| - if (resolvedComponents != null) | |
| - { | |
| - return resolvedComponents; | |
| - } | |
| - | |
| resolvedComponents = new HashSet<Bean<?>>(); | |
| boolean returnAll = false; | |
| Index: webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceCacheKey.java | |
| =================================================================== | |
| --- webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceCacheKey.java (revision 0) | |
| +++ webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceCacheKey.java (working copy) | |
| @@ -0,0 +1,400 @@ | |
| +/* | |
| + * Licensed to the Apache Software Foundation (ASF) under one | |
| + * or more contributor license agreements. See the NOTICE file | |
| + * distributed with this work for additional information | |
| + * regarding copyright ownership. The ASF licenses this file | |
| + * to you under the Apache License, Version 2.0 (the | |
| + * "License"); you may not use this file except in compliance | |
| + * with the License. You may obtain a copy of the License at | |
| + * | |
| + * http://www.apache.org/licenses/LICENSE-2.0 | |
| + * | |
| + * Unless required by applicable law or agreed to in writing, | |
| + * software distributed under the License is distributed on an | |
| + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| + * KIND, either express or implied. See the License for the | |
| + * specific language governing permissions and limitations | |
| + * under the License. | |
| + */ | |
| +package org.apache.webbeans.inject.instance; | |
| + | |
| +import org.apache.webbeans.util.AnnotationUtil; | |
| + | |
| +import javax.enterprise.util.Nonbinding; | |
| +import java.lang.annotation.Annotation; | |
| +import java.lang.reflect.Array; | |
| +import java.lang.reflect.Method; | |
| +import java.lang.reflect.Type; | |
| +import java.util.Arrays; | |
| +import java.util.Comparator; | |
| + | |
| +public class InstanceCacheKey { | |
| + private static final Comparator<Annotation> ANNOTATION_COMPARATOR = new AnnotationComparator(); | |
| + | |
| + private final Annotation qualifier; | |
| + private final Annotation qualifiers[]; | |
| + private final int hashCode; | |
| + | |
| + public InstanceCacheKey(final Annotation[] qualifiers) { | |
| + final int length = qualifiers != null ? qualifiers.length : 0; | |
| + if (length == 0) | |
| + { | |
| + this.qualifier = null; | |
| + this.qualifiers = null; | |
| + } | |
| + else if (length == 1) | |
| + { | |
| + this.qualifier = qualifiers[0]; | |
| + this.qualifiers = null; | |
| + } | |
| + else | |
| + { | |
| + this.qualifier = null; | |
| + // to save array creations, we only create an array, if we have more than one annotation | |
| + this.qualifiers = new Annotation[length]; | |
| + System.arraycopy(qualifiers, 0, this.qualifiers, 0, length); | |
| + Arrays.sort(this.qualifiers, ANNOTATION_COMPARATOR); | |
| + } | |
| + | |
| + hashCode = computeHashCode(); | |
| + } | |
| + | |
| + private int computeHashCode() { | |
| + int computedHashCode = 0; | |
| + if (qualifier != null) | |
| + { | |
| + computedHashCode = 31 * computedHashCode + getQualifierHashCode(qualifier); | |
| + } | |
| + if (qualifiers != null) | |
| + { | |
| + for (Annotation qualifier1 : qualifiers) { | |
| + computedHashCode = 31 * computedHashCode + getQualifierHashCode(qualifier1); | |
| + } | |
| + } | |
| + return computedHashCode; | |
| + } | |
| + | |
| + @Override | |
| + public boolean equals(Object o) { | |
| + if (this == o) return true; | |
| + if (!(o instanceof InstanceCacheKey)) return false; | |
| + | |
| + InstanceCacheKey that = (InstanceCacheKey) o; | |
| + | |
| + if (qualifier != null ? !qualifierEquals(qualifier, that.qualifier) : that.qualifier != null) | |
| + { | |
| + return false; | |
| + } | |
| + if (!qualifierArrayEquals(qualifiers, that.qualifiers)) | |
| + { | |
| + return false; | |
| + } | |
| + | |
| + return true; | |
| + } | |
| + | |
| + @Override | |
| + public int hashCode() { | |
| + return hashCode; | |
| + } | |
| + | |
| + /** | |
| + * Implements the equals() method for qualifiers, which ignores {@link javax.enterprise.util.Nonbinding} members. | |
| + */ | |
| + private boolean qualifierEquals(Annotation qualifier1, Annotation qualifier2) | |
| + { | |
| + return ANNOTATION_COMPARATOR.compare(qualifier1, qualifier2) == 0; | |
| + } | |
| + | |
| + @Override // for debugging | |
| + public String toString() | |
| + { | |
| + return "" + (qualifiers == null ? qualifier : Arrays.asList(qualifiers)); | |
| + } | |
| + | |
| + private boolean qualifierArrayEquals(Annotation[] qualifiers1, Annotation[] qualifiers2) | |
| + { | |
| + if (qualifiers1 == qualifiers2) | |
| + { | |
| + return true; | |
| + } | |
| + else if (qualifiers1 == null || qualifiers2 == null) | |
| + { | |
| + return false; | |
| + } | |
| + if (qualifiers1.length != qualifiers2.length) | |
| + { | |
| + return false; | |
| + } | |
| + for (int i = 0; i < qualifiers1.length; i++) | |
| + { | |
| + Annotation a1 = qualifiers1[i]; | |
| + Annotation a2 = qualifiers2[i]; | |
| + if (a1 == null ? a2 != null : !qualifierEquals(a1, a2)) | |
| + { | |
| + return false; | |
| + } | |
| + } | |
| + | |
| + return true; | |
| + } | |
| + | |
| + private static Class getAnnotationClass(Class a) | |
| + { | |
| + for (Class i : a.getInterfaces()) | |
| + { | |
| + if (i.isAnnotation()) | |
| + { | |
| + return i; | |
| + } | |
| + } | |
| + return null; | |
| + } | |
| + | |
| + /** | |
| + * Helper method for calculating the hashCode of an annotation. | |
| + */ | |
| + private static Object callMethod(Object instance, Method method) | |
| + { | |
| + try | |
| + { | |
| + if (!method.isAccessible()) | |
| + { | |
| + method.setAccessible(true); | |
| + } | |
| + | |
| + return method.invoke(instance, AnnotationUtil.EMPTY_OBJECT_ARRAY); | |
| + } | |
| + catch (Exception e) | |
| + { | |
| + throw new RuntimeException("Exception in method call : " + method.getName(), e); | |
| + } | |
| + | |
| + } | |
| + | |
| + protected boolean hasQualifiers() { | |
| + return qualifier != null || qualifiers != null; | |
| + } | |
| + | |
| + /** | |
| + * Calculate the hashCode() of a qualifier, which ignores {@link Nonbinding} members. | |
| + */ | |
| + private int getQualifierHashCode(Annotation a) | |
| + { | |
| + Class annotationClass = getAnnotationClass(a.getClass()); | |
| + | |
| + if (annotationClass == null) | |
| + { | |
| + return getTypeHashCode(a.getClass()); | |
| + } | |
| + | |
| + // the hashCode of an Annotation is calculated solely via the hashCodes | |
| + // of it's members. If there are no members, it is 0. | |
| + // thus we first need to get the annotation-class hashCode | |
| + int hashCode = getTypeHashCode(annotationClass); | |
| + | |
| + // and now add the hashCode of all it's Nonbinding members | |
| + // the following algorithm is defined by the Annotation class definition | |
| + // see the JavaDoc for Annotation! | |
| + // we only change it so far that we skip evaluating @Nonbinding members | |
| + final Method[] members = annotationClass.getDeclaredMethods(); | |
| + | |
| + for (Method member : members) | |
| + { | |
| + if (member.isAnnotationPresent(Nonbinding.class)) | |
| + { | |
| + // ignore the non binding | |
| + continue; | |
| + } | |
| + | |
| + // Member value | |
| + final Object object = callMethod(a, member); | |
| + final int value; | |
| + if(object.getClass().isArray()) | |
| + { | |
| + Class<?> type = object.getClass().getComponentType(); | |
| + if(type.isPrimitive()) | |
| + { | |
| + if(Long.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((long[]) object); | |
| + } | |
| + else if(Integer.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((int[])object); | |
| + } | |
| + else if(Short.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((short[])object); | |
| + } | |
| + else if(Double.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((double[])object); | |
| + } | |
| + else if(Float.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((float[])object); | |
| + } | |
| + else if(Boolean.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((boolean[])object); | |
| + } | |
| + else if(Byte.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((byte[])object); | |
| + } | |
| + else if(Character.TYPE == type) | |
| + { | |
| + value = Arrays.hashCode((char[])object); | |
| + } | |
| + else | |
| + { | |
| + value = 0; | |
| + } | |
| + } | |
| + else | |
| + { | |
| + value = Arrays.hashCode((Object[])object); | |
| + } | |
| + } | |
| + else | |
| + { | |
| + value = object.hashCode(); | |
| + } | |
| + | |
| + hashCode = 29 * hashCode + value; | |
| + hashCode = 29 * hashCode + member.getName().hashCode(); | |
| + } | |
| + | |
| + return hashCode; | |
| + } | |
| + | |
| + /** | |
| + * We need this method as some weird JVMs return 0 as hashCode for classes. | |
| + * In that case we return the hashCode of the String. | |
| + */ | |
| + protected int getTypeHashCode(Type type) | |
| + { | |
| + int typeHash = type.hashCode(); | |
| + if (typeHash == 0 && type instanceof Class) | |
| + { | |
| + return ((Class)type).getName().hashCode(); | |
| + // the type.toString() is always the same: "java.lang.Class@<hexid>" | |
| + // was: return type.toString().hashCode(); | |
| + } | |
| + | |
| + return typeHash; | |
| + } | |
| + | |
| + /** | |
| + * to keep the annotations ordered. | |
| + */ | |
| + private static class AnnotationComparator implements Comparator<Annotation> | |
| + { | |
| + | |
| + // Notice: Sorting is a bit costly, but the use of this code is very rar. | |
| + public int compare(Annotation annotation1, Annotation annotation2) | |
| + { | |
| + final Class<? extends Annotation> type1 = annotation1.annotationType(); | |
| + final Class<? extends Annotation> type2 = annotation2.annotationType(); | |
| + final int temp = type1.getName().compareTo(type2.getName()); | |
| + if (temp != 0) | |
| + { | |
| + return temp; | |
| + } | |
| + final Method[] member1 = type1.getDeclaredMethods(); | |
| + final Method[] member2 = type2.getDeclaredMethods(); | |
| + | |
| + // TBD: the order of the list of members seems to be deterministic | |
| + | |
| + int i = 0; | |
| + int j = 0; | |
| + final int length1 = member1.length; | |
| + final int length2 = member2.length; | |
| + | |
| + // find next nonbinding | |
| + for (;; i++, j++) | |
| + { | |
| + while (i < length1 && member1[i].isAnnotationPresent(Nonbinding.class)) | |
| + { | |
| + i++; | |
| + } | |
| + while (j < length2 && member2[j].isAnnotationPresent(Nonbinding.class)) | |
| + { | |
| + j++; | |
| + } | |
| + if (i >= length1 && j >= length2) | |
| + { // both ended | |
| + return 0; | |
| + } | |
| + else if (i >= length1) | |
| + { // #1 ended | |
| + return 1; | |
| + } | |
| + else if (j >= length2) | |
| + { // #2 ended | |
| + return -1; | |
| + } | |
| + else | |
| + { // not ended | |
| + int c = member1[i].getName().compareTo(member2[j].getName()); | |
| + if (c != 0) | |
| + { | |
| + return c; | |
| + } | |
| + final Object value1 = callMethod(annotation1, member1[i]); | |
| + final Object value2 = callMethod(annotation2, member2[j]); | |
| + assert value1.getClass().equals(value2.getClass()); | |
| + | |
| + if (value1 instanceof Comparable) | |
| + { | |
| + c = ((Comparable)value1).compareTo(value2); | |
| + if (c != 0) | |
| + { | |
| + return c; | |
| + } | |
| + } | |
| + else if (value1.getClass().isArray()) | |
| + { | |
| + c = value1.getClass().getComponentType().getName() | |
| + .compareTo(value2.getClass().getComponentType().getName()); | |
| + if (c != 0) | |
| + { | |
| + return c; | |
| + } | |
| + | |
| + final int length = Array.getLength(value1); | |
| + c = length - Array.getLength(value2); | |
| + if (c != 0) | |
| + { | |
| + return c; | |
| + } | |
| + for (int k = 0; k < length; k++) | |
| + { | |
| + c = ((Comparable)Array.get(value1, k)).compareTo(Array.get(value2, k)); | |
| + if (c != 0) | |
| + { | |
| + return c; | |
| + } | |
| + } | |
| + | |
| + } | |
| + else if (value1 instanceof Class) | |
| + { | |
| + | |
| + c = ((Class)value1).getName().compareTo(((Class) value2).getName()); | |
| + if (c != 0) | |
| + { | |
| + return c; | |
| + } | |
| + } | |
| + else | |
| + { | |
| + // valid types for members are only Comparable, Arrays, or Class | |
| + assert false; | |
| + } | |
| + } | |
| + } | |
| + } | |
| + } | |
| +} | |
| Index: webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceImpl.java | |
| =================================================================== | |
| --- webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceImpl.java (revision 1436220) | |
| +++ webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceImpl.java (working copy) | |
| @@ -18,32 +18,38 @@ | |
| */ | |
| package org.apache.webbeans.inject.instance; | |
| +import org.apache.webbeans.config.WebBeansContext; | |
| +import org.apache.webbeans.container.BeanCacheKey; | |
| +import org.apache.webbeans.container.BeanManagerImpl; | |
| +import org.apache.webbeans.container.InjectionResolver; | |
| +import org.apache.webbeans.context.creational.CreationalContextImpl; | |
| +import org.apache.webbeans.portable.InjectionPointProducer; | |
| +import org.apache.webbeans.util.ClassUtil; | |
| +import org.apache.webbeans.util.InjectionExceptionUtil; | |
| +import org.apache.webbeans.util.OwbCustomObjectInputStream; | |
| +import org.apache.webbeans.util.WebBeansUtil; | |
| + | |
| +import javax.enterprise.context.spi.CreationalContext; | |
| +import javax.enterprise.inject.Instance; | |
| +import javax.enterprise.inject.spi.Bean; | |
| +import javax.enterprise.inject.spi.InjectionPoint; | |
| +import javax.enterprise.util.TypeLiteral; | |
| import java.io.IOException; | |
| import java.io.ObjectInputStream; | |
| import java.io.ObjectOutputStream; | |
| import java.io.Serializable; | |
| import java.lang.annotation.Annotation; | |
| import java.lang.reflect.Type; | |
| +import java.util.Arrays; | |
| +import java.util.Collections; | |
| import java.util.HashSet; | |
| import java.util.Iterator; | |
| import java.util.Set; | |
| +import java.util.concurrent.ConcurrentHashMap; | |
| +import java.util.concurrent.ConcurrentMap; | |
| -import javax.enterprise.context.spi.CreationalContext; | |
| -import javax.enterprise.inject.Instance; | |
| -import javax.enterprise.inject.spi.Bean; | |
| -import javax.enterprise.inject.spi.InjectionPoint; | |
| -import javax.enterprise.util.TypeLiteral; | |
| +import static org.apache.webbeans.util.InjectionExceptionUtil.throwAmbiguousResolutionException; | |
| -import org.apache.webbeans.config.WebBeansContext; | |
| -import org.apache.webbeans.container.BeanManagerImpl; | |
| -import org.apache.webbeans.container.InjectionResolver; | |
| -import org.apache.webbeans.context.creational.CreationalContextImpl; | |
| -import org.apache.webbeans.portable.InjectionPointProducer; | |
| -import org.apache.webbeans.util.ClassUtil; | |
| -import org.apache.webbeans.util.InjectionExceptionUtil; | |
| -import org.apache.webbeans.util.OwbCustomObjectInputStream; | |
| -import org.apache.webbeans.util.WebBeansUtil; | |
| - | |
| /** | |
| * Implements the {@link Instance} interface. | |
| * | |
| @@ -62,12 +68,17 @@ | |
| private InjectionPoint injectionPoint; | |
| /** Qualifier annotations appeared on the injection point */ | |
| - private Set<Annotation> qualifierAnnotations = new HashSet<Annotation>(); | |
| + private Annotation[] anns; | |
| private WebBeansContext webBeansContext; | |
| private CreationalContext<?> parentCreationalContext; | |
| + // cache for perfs, transient is useless since we manage the serial ourself byt just for doc purpose | |
| + private transient BeanCacheKey cacheKey = null; | |
| + private transient Set<Bean<?>> beans = null; | |
| + private transient final ConcurrentMap<InstanceCacheKey, InstanceImpl<T>> instancesCache = new ConcurrentHashMap<InstanceCacheKey, InstanceImpl<T>>(); | |
| + | |
| /** | |
| * Creates new instance. | |
| * | |
| @@ -75,7 +86,6 @@ | |
| * @param injectionPoint null or injection point | |
| * @param webBeansContext | |
| * @param creationalContext will get used for creating @Dependent beans | |
| - * @param ownerInstance the object the current Instance got injected into | |
| * @param annotations qualifier annotations | |
| */ | |
| public InstanceImpl(Type injectionClazz, InjectionPoint injectionPoint, WebBeansContext webBeansContext, | |
| @@ -85,13 +95,43 @@ | |
| this.injectionPoint = injectionPoint; | |
| this.parentCreationalContext = creationalContext; | |
| - for (Annotation ann : annotations) | |
| + final Set<Annotation> qualifierAnnotations = new HashSet<Annotation>(); | |
| + Collections.addAll(qualifierAnnotations, annotations); | |
| + anns = new Annotation[qualifierAnnotations.size()]; | |
| + anns = qualifierAnnotations.toArray(anns); | |
| + | |
| + this.webBeansContext = webBeansContext; | |
| + | |
| + init(); | |
| + } | |
| + | |
| + private void computeCacheKey() { | |
| + InjectionResolver injectionResolver = webBeansContext.getBeanManagerImpl().getInjectionResolver(); | |
| + | |
| + Bean<?> injectionPointBean = injectionPoint.getBean(); | |
| + Class<?> injectionPointClass = null; | |
| + if (injectionPointBean != null) | |
| { | |
| - qualifierAnnotations.add(ann); | |
| + injectionPointClass = injectionPointBean.getBeanClass(); | |
| } | |
| - this.webBeansContext = webBeansContext; | |
| + | |
| + cacheKey = injectionResolver.computeKey(injectionClazz, injectionPointClass, anns); | |
| } | |
| + private static Bean<?> quickResolve(final Set<Bean<?>> set) { // we already did resolveAll() so no need to redo it | |
| + if (set.isEmpty()) | |
| + { | |
| + return null; | |
| + } | |
| + | |
| + if(set.size() > 1) | |
| + { | |
| + throwAmbiguousResolutionException(set); | |
| + } | |
| + | |
| + return set.iterator().next(); | |
| + } | |
| + | |
| /** | |
| * Returns the bean instance with given qualifier annotations. | |
| * | |
| @@ -105,14 +145,9 @@ | |
| InjectionPointProducer.setThreadLocal(injectionPoint); | |
| try | |
| { | |
| - Annotation[] anns = new Annotation[qualifierAnnotations.size()]; | |
| - anns = qualifierAnnotations.toArray(anns); | |
| - | |
| - Set<Bean<?>> beans = resolveBeans(); | |
| - | |
| BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl(); | |
| - Bean<?> bean = beanManager.resolve(beans); | |
| + Bean<?> bean = quickResolve(beans); | |
| if (bean == null) | |
| { | |
| @@ -150,22 +185,19 @@ | |
| * | |
| * @return set of resolved beans | |
| */ | |
| - private Set<Bean<?>> resolveBeans() | |
| + private void resolveBeans() | |
| { | |
| - Annotation[] anns = new Annotation[qualifierAnnotations.size()]; | |
| - anns = qualifierAnnotations.toArray(anns); | |
| - | |
| InjectionResolver injectionResolver = webBeansContext.getBeanManagerImpl().getInjectionResolver(); | |
| - InjectionResolver resolver = injectionResolver; | |
| Bean<?> injectionPointBean = injectionPoint.getBean(); | |
| Class<?> injectionPointClass = null; | |
| if (injectionPointBean != null) | |
| { | |
| injectionPointClass = injectionPointBean.getBeanClass(); | |
| } | |
| - Set<Bean<?>> beans = resolver.implResolveByType(injectionClazz, injectionPointClass, anns); | |
| - return resolver.resolveAll(beans); | |
| + | |
| + Set<Bean<?>> beanSet = injectionResolver.implResolveByType(cacheKey, injectionClazz, injectionPointClass, anns); | |
| + beans = injectionResolver.resolveAll(beanSet); | |
| } | |
| /** | |
| @@ -173,9 +205,7 @@ | |
| */ | |
| public boolean isAmbiguous() | |
| { | |
| - Set<Bean<?>> beans = resolveBeans(); | |
| - | |
| - return beans.size() > 1 ? true : false; | |
| + return beans.size() > 1; | |
| } | |
| /** | |
| @@ -183,9 +213,7 @@ | |
| */ | |
| public boolean isUnsatisfied() | |
| { | |
| - Set<Bean<?>> beans = resolveBeans(); | |
| - | |
| - return beans.size() == 0 ? true : false; | |
| + return beans.isEmpty(); | |
| } | |
| /** | |
| @@ -193,10 +221,23 @@ | |
| */ | |
| public Instance<T> select(Annotation... qualifiers) | |
| { | |
| - Annotation[] newQualifiersArray = getAdditionalQualifiers(qualifiers); | |
| - InstanceImpl<T> newInstance = new InstanceImpl<T>(injectionClazz, injectionPoint, webBeansContext, parentCreationalContext, newQualifiersArray); | |
| + final InstanceCacheKey key = new InstanceCacheKey(qualifiers); | |
| - return newInstance; | |
| + InstanceImpl<T> instance = instancesCache.get(key); | |
| + if (instance != null) { | |
| + return instance; | |
| + } | |
| + | |
| + final Annotation[] newQualifiersArray = getAdditionalQualifiers(qualifiers); | |
| + | |
| + instance = new InstanceImpl<T>(injectionClazz, injectionPoint, webBeansContext, parentCreationalContext, newQualifiersArray); | |
| + InstanceImpl<T> old = instancesCache.putIfAbsent(key, instance); | |
| + if (old != null) | |
| + { | |
| + instance = old; | |
| + } | |
| + | |
| + return instance; | |
| } | |
| /** | |
| @@ -208,7 +249,7 @@ | |
| private Annotation[] getAdditionalQualifiers(Annotation[] qualifiers) | |
| { | |
| webBeansContext.getAnnotationManager().checkQualifierConditions(qualifiers); | |
| - Set<Annotation> newQualifiers = new HashSet<Annotation>(qualifierAnnotations); | |
| + Set<Annotation> newQualifiers = new HashSet<Annotation>(Arrays.asList(anns)); | |
| if (qualifiers != null && qualifiers.length > 0) | |
| { | |
| @@ -225,7 +266,7 @@ | |
| Annotation[] newQualifiersArray = new Annotation[newQualifiers.size()]; | |
| newQualifiersArray = newQualifiers.toArray(newQualifiersArray); | |
| - | |
| + | |
| return newQualifiersArray; | |
| } | |
| @@ -245,9 +286,7 @@ | |
| Annotation[] newQualifiers = getAdditionalQualifiers(qualifiers); | |
| - InstanceImpl<U> newInstance = new InstanceImpl(sub, injectionPoint, webBeansContext, parentCreationalContext, newQualifiers); | |
| - | |
| - return newInstance; | |
| + return new InstanceImpl(sub, injectionPoint, webBeansContext, parentCreationalContext, newQualifiers); | |
| } | |
| /** | |
| @@ -264,7 +303,6 @@ | |
| @SuppressWarnings("unchecked") | |
| public Iterator<T> iterator() | |
| { | |
| - Set<Bean<?>> beans = resolveBeans(); | |
| Set<T> instances = new HashSet<T>(); | |
| InjectionPointProducer.setThreadLocal(injectionPoint); | |
| try | |
| @@ -287,7 +325,7 @@ | |
| { | |
| ObjectOutputStream oos = new ObjectOutputStream(op); | |
| oos.writeObject(injectionClazz); | |
| - oos.writeObject(qualifierAnnotations); | |
| + oos.writeObject(anns); | |
| oos.writeObject(injectionPoint); | |
| oos.flush(); | |
| @@ -298,11 +336,18 @@ | |
| webBeansContext = WebBeansContext.currentInstance(); | |
| final ObjectInputStream inputStream = new OwbCustomObjectInputStream(in, WebBeansUtil.getCurrentClassLoader()); | |
| injectionClazz = (Type)inputStream.readObject(); | |
| - qualifierAnnotations = (Set<Annotation>)inputStream.readObject(); | |
| + anns = (Annotation[])inputStream.readObject(); | |
| injectionPoint = (InjectionPoint) inputStream.readObject(); | |
| + | |
| + init(); | |
| } | |
| - | |
| + private void init() { | |
| + computeCacheKey(); | |
| + resolveBeans(); | |
| + } | |
| + | |
| + | |
| public String toString() | |
| { | |
| StringBuilder builder = new StringBuilder(); | |
| @@ -312,7 +357,7 @@ | |
| builder.append(",with qualifier annotations {"); | |
| int i = 0; | |
| - for (Annotation qualifier : qualifierAnnotations) | |
| + for (Annotation qualifier : anns) | |
| { | |
| if (i != 0) | |
| { | |
| @@ -320,11 +365,11 @@ | |
| } | |
| builder.append(qualifier.toString()); | |
| + i++; | |
| } | |
| builder.append("}"); | |
| return builder.toString(); | |
| } | |
| - | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment