You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by st...@apache.org on 2012/09/12 19:44:40 UTC
svn commit: r1384049 - in
/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container:
BeanCacheKey.java InjectionResolver.java
Author: struberg
Date: Wed Sep 12 17:44:39 2012
New Revision: 1384049
URL: http://svn.apache.org/viewvc?rev=1384049&view=rev
Log:
OWB-703 fix bean cache
thanks to Udo Schnurrpfeil (apacheId lofwyr) for the patch!
Applied with slight tweaks (cache the hashCode and rename to BeanCacheKey)
Added:
openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java (with props)
Modified:
openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java
Added: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java?rev=1384049&view=auto
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java (added)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java Wed Sep 12 17:44:39 2012
@@ -0,0 +1,254 @@
+/*
+ * 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.container;
+
+import org.apache.webbeans.util.AnnotationUtil;
+
+import javax.enterprise.util.Nonbinding;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+final class BeanCacheKey
+{
+ private Type type;
+ private String path;
+ private Annotation qualifier;
+ private Annotation qualifiers[];
+ private int hashCode = -1;
+
+
+ public BeanCacheKey( Type type, String path, Annotation... qualifiers )
+ {
+ this.type = type;
+ this.path = path;
+ final int length = qualifiers.length;
+ if (length == 0)
+ {
+ // do nothing
+ }
+ else if (length == 1)
+ {
+ qualifier = qualifiers[0];
+ }
+ else
+ {
+ // to save array creations, we only create an array, if we have more than one annotation
+ this.qualifiers = new Annotation[length];
+ // TBD: is the order of the qualifiers always the same?
+ System.arraycopy(qualifiers, 0, this.qualifiers, 0, length);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ BeanCacheKey cacheKey = (BeanCacheKey) o;
+
+ if (!type.equals(cacheKey.type))
+ {
+ return false;
+ }
+ if (qualifier != null ? !qualifier.equals(cacheKey.qualifier) : cacheKey.qualifier != null)
+ {
+ return false;
+ }
+ if (!Arrays.equals(qualifiers, cacheKey.qualifiers))
+ {
+ return false;
+ }
+ if (path != null ? !path.equals(cacheKey.path) : cacheKey.path != null)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ if (hashCode != -1)
+ {
+ return hashCode;
+ }
+
+ int result = getTypeHashCode(type);
+ result = 31 * result + (path != null ? path.hashCode() : 0);
+ result = 31 * result + (qualifier != null ? getQualifierHashCode(qualifier) : 0);
+ if (qualifiers != null)
+ {
+ for (int i = 0; i < qualifiers.length; i++)
+ {
+ result = 31 * result + getQualifierHashCode(qualifiers[i]);
+ }
+ }
+ hashCode = result;
+ 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.
+ */
+ 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>"
+ // return type.toString().hashCode();
+ }
+
+ return typeHash;
+ }
+
+ /**
+ * Calculate the hashCode of a Qualifier
+ */
+ 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
+ Method[] methods = annotationClass.getDeclaredMethods();
+
+ for (Method method : methods)
+ {
+ if (method.isAnnotationPresent(Nonbinding.class))
+ {
+ continue;
+ }
+
+ // Member value
+ Object object = callMethod(a, method);
+ int value = 0;
+ 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((Integer[])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((Long[])object);
+ }
+ else if(Byte.TYPE == type)
+ {
+ value = Arrays.hashCode((Byte[])object);
+ }
+ else if(Character.TYPE == type)
+ {
+ value = Arrays.hashCode((Character[])object);
+ }
+ }
+ else
+ {
+ value = Arrays.hashCode((Object[])object);
+ }
+ }
+ else
+ {
+ value = object.hashCode();
+ }
+
+ hashCode = 29 * hashCode + value;
+ hashCode = 29 * hashCode + method.getName().hashCode();
+ hashCode = 29 * hashCode + a.hashCode();
+ }
+
+ return hashCode;
+ }
+
+ private 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 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);
+ }
+
+ }
+}
Propchange: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanCacheKey.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java
URL: http://svn.apache.org/viewvc/openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java?rev=1384049&r1=1384048&r2=1384049&view=diff
==============================================================================
--- openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java (original)
+++ openwebbeans/trunk/webbeans-impl/src/main/java/org/apache/webbeans/container/InjectionResolver.java Wed Sep 12 17:44:39 2012
@@ -19,10 +19,8 @@
package org.apache.webbeans.container;
import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
@@ -37,7 +35,6 @@ import javax.enterprise.inject.Instance;
import javax.enterprise.inject.New;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.InjectionPoint;
-import javax.enterprise.util.Nonbinding;
import org.apache.webbeans.annotation.AnyLiteral;
import org.apache.webbeans.annotation.DefaultLiteral;
@@ -83,9 +80,9 @@ public class InjectionResolver
/**
* This Map contains all resolved beans via it's type and qualifiers.
* If a bean have resolved as not existing, the entry will contain <code>null</code> as value.
- * The Long key is a hashCode, see {@link #getBeanCacheKey(Type, String, Annotation...)}
+ * The Long key is a hashCode, see {@link BeanCacheKey#BeanCacheKey(Type, String, Annotation...)}
*/
- private Map<Long, Set<Bean<?>>> resolvedBeansByType = new ConcurrentHashMap<Long, Set<Bean<?>>>();
+ private Map<BeanCacheKey, Set<Bean<?>>> resolvedBeansByType = new ConcurrentHashMap<BeanCacheKey, Set<Bean<?>>>();
/**
* This Map contains all resolved beans via it's ExpressionLanguage name.
@@ -466,7 +463,7 @@ public class InjectionResolver
}
}
- Long cacheKey = getBeanCacheKey(injectionPointType, bdaBeansXMLFilePath, qualifiers);
+ BeanCacheKey cacheKey = new BeanCacheKey(injectionPointType, bdaBeansXMLFilePath, qualifiers);
Set<Bean<?>> resolvedComponents = resolvedBeansByType.get(cacheKey);
if (resolvedComponents != null)
@@ -529,163 +526,6 @@ public class InjectionResolver
return resolvedComponents;
}
- private Long getBeanCacheKey(Type injectionPointType, String bdaBeansXMLPath, Annotation... qualifiers)
- {
-
- long cacheKey = getTypeHashCode(injectionPointType);
-
- if (bdaBeansXMLPath != null)
- {
- cacheKey += 29L * bdaBeansXMLPath.hashCode();
- }
-
- for (Annotation a : qualifiers)
- {
- cacheKey += 29L * getQualifierHashCode(a);
- }
- return cacheKey;
- }
-
- /**
- * 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)
- {
- return type.toString().hashCode();
- }
-
- return typeHash;
- }
-
- /**
- * Calculate the hashCode of a Qualifier
- */
- private long 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
- long 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
- Method[] methods = annotationClass.getDeclaredMethods();
-
- for (Method method : methods)
- {
- if (method.isAnnotationPresent(Nonbinding.class))
- {
- continue;
- }
-
- // Member name
- int name = 127 * method.getName().hashCode();
-
- // Member value
- Object object = callMethod(a, method);
- int value = 0;
- 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((Integer[])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((Long[])object);
- }
- else if(Byte.TYPE == type)
- {
- value = Arrays.hashCode((Byte[])object);
- }
- else if(Character.TYPE == type)
- {
- value = Arrays.hashCode((Character[])object);
- }
- }
- else
- {
- value = Arrays.hashCode((Object[])object);
- }
- }
- else
- {
- value = object.hashCode();
- }
-
- hashCode += name ^ value;
-
-
- hashCode += 29L * a.hashCode();
- }
-
- return hashCode;
- }
-
- private 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 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);
- }
- }
-
/**
* Returns specialized beans if exists, otherwise return input result
*