org.apache.webbeans.portable.AnnotatedElementFactory Maven / Gradle / Ivy
/*
* 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.portable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import org.apache.webbeans.config.OWBLogConst;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.logger.WebBeansLoggerFacade;
import org.apache.webbeans.util.Asserts;
import org.apache.webbeans.util.ClassUtil;
/**
* Factory for {@link javax.enterprise.inject.spi.Annotated} elements.
*
* @version $Rev$ $Date$
*/
public final class AnnotatedElementFactory
{
public static final String OWB_DEFAULT_KEY = "OWB_DEFAULT_KEY";
// Logger instance
private static final Logger logger = WebBeansLoggerFacade.getLogger(AnnotatedElementFactory.class);
/**
* Cache of the initial AnnotatedTypes
*/
private ConcurrentMap, ConcurrentMap>> annotatedTypeCache =
new ConcurrentHashMap<>();
/**
* Cache of modified AnnotatedTypes.
*/
private ConcurrentMap, ConcurrentMap>> modifiedAnnotatedTypeCache =
new ConcurrentHashMap<>();
//Cache of AnnotatedConstructor
private ConcurrentMap, AnnotatedConstructor>> annotatedConstructorCache =
new ConcurrentHashMap<>();
//Cache of AnnotatedMethod
private ConcurrentMap> annotatedMethodCache =
new ConcurrentHashMap<>();
//Cache of AnnotatedField
private ConcurrentMap> annotatedFieldCache =
new ConcurrentHashMap<>();
//Cache of AnnotatedMethod
private ConcurrentMap, Set>> annotatedMethodsOfTypeCache =
new ConcurrentHashMap<>();
private WebBeansContext webBeansContext;
/**
* No instantiate.
*/
public AnnotatedElementFactory(WebBeansContext webBeansContext)
{
this.webBeansContext = webBeansContext;
}
/**
* Get an already registered AnnotatedType. This will NOT create a new one!
* The returned AnnotatedType will reflect all the changes made during the
* boot process so far.
* If there was no AnnotatedType created yet for the given Class,
* null
will be returned.
*/
public AnnotatedType getAnnotatedType(Class annotatedClass)
{
ConcurrentMap> modifiedAnnotatedClasses = modifiedAnnotatedTypeCache.get(annotatedClass);
if (modifiedAnnotatedClasses != null)
{
AnnotatedType annotatedType = (AnnotatedType) modifiedAnnotatedClasses.get(OWB_DEFAULT_KEY);
if (annotatedType != null)
{
return annotatedType;
}
}
return getAnnotatedTypeCache(annotatedClass).get(OWB_DEFAULT_KEY);
}
/**
* Get all already registered AnnotatedTypes of the specified type. This will NOT create a new one!
* @param annotatedClass
* @param
* @return AnnotatedType
*/
public Iterable> getAnnotatedTypes(Class annotatedClass)
{
return getAnnotatedTypeCache(annotatedClass).values();
}
/**
* This method will get used to manually add AnnoatedTypes to our storage.
* Those AnnotatedTypes are coming from Extensions and get registered e.g. via
* {@link javax.enterprise.inject.spi.BeforeBeanDiscovery#addAnnotatedType(AnnotatedType)}
*
* Sets the annotatedType and replace the given one.
* @param annotatedType
* @param
* @return the previously registered AnnotatedType or null if not previously defined.
*/
public AnnotatedType setAnnotatedType(AnnotatedType annotatedType)
{
return setAnnotatedType(annotatedType, OWB_DEFAULT_KEY);
}
public AnnotatedType setAnnotatedType(AnnotatedType annotatedType, String id)
{
Class type = annotatedType.getJavaClass();
ConcurrentMap> annotatedTypes = modifiedAnnotatedTypeCache.get(type);
if (annotatedTypes == null)
{
annotatedTypes = new ConcurrentHashMap<>();
}
ConcurrentMap> oldAnnotatedTypes = modifiedAnnotatedTypeCache.putIfAbsent(type, annotatedTypes);
if (oldAnnotatedTypes != null)
{
annotatedTypes = oldAnnotatedTypes;
}
return (AnnotatedType) annotatedTypes.put(id, annotatedType);
}
/**
* Creates and configures a new annotated type.
* This always returns the fresh AnnotatedTypes without any modifications
* applied by Extensions!.
*
* To get any AnnotatedTypes which are modified during the boot process you shall use
* {@link #getAnnotatedType(Class)}.
*
* @param class info
* @param annotatedClass annotated class
* @return new annotated type
*/
public AnnotatedType newAnnotatedType(Class annotatedClass)
{
Asserts.assertNotNull(annotatedClass, "annotatedClass");
ConcurrentMap> annotatedTypes = getAnnotatedTypeCache(annotatedClass);
AnnotatedType annotatedType = annotatedTypes.get(OWB_DEFAULT_KEY);
if(annotatedType == null)
{
try
{
AnnotatedType super X> supertype = null;
if (annotatedClass.getSuperclass() != null && !annotatedClass.getSuperclass().equals(Object.class))
{
supertype = newAnnotatedType(annotatedClass.getSuperclass());
}
annotatedType = new AnnotatedTypeImpl<>(webBeansContext, annotatedClass, supertype);
AnnotatedType oldType = annotatedTypes.putIfAbsent(OWB_DEFAULT_KEY, annotatedType);
if(oldType != null)
{
annotatedType = oldType;
}
}
catch (Exception e)
{
if (e instanceof ClassNotFoundException || e instanceof ArrayStoreException)
{
if (logger.isLoggable(Level.SEVERE))
{
logger.log(Level.SEVERE, WebBeansLoggerFacade.constructMessage(OWBLogConst.ERROR_0027, annotatedClass.getName(), e.getCause()), e);
}
annotatedType = null;
}
else
{
throw new RuntimeException(e);
}
}
catch (NoClassDefFoundError ncdfe)
{
if (logger.isLoggable(Level.SEVERE))
{
logger.log(Level.SEVERE, WebBeansLoggerFacade.constructMessage(OWBLogConst.ERROR_0027, annotatedClass.getName(), ncdfe.getCause()), ncdfe);
}
annotatedType = null;
}
}
return annotatedType;
}
/**
* Creates and configures new annotated constructor.
*
* @param declaring class
* @param constructor constructor
* @return new annotated constructor
*/
@SuppressWarnings("unchecked")
public AnnotatedConstructor newAnnotatedConstructor(Constructor constructor, AnnotatedType declaringClass)
{
Asserts.assertNotNull(constructor, "constructor");
Asserts.assertNotNull(declaringClass, "declaringClass");
AnnotatedConstructorImpl annConstructor;
if(annotatedConstructorCache.containsKey(constructor))
{
annConstructor = (AnnotatedConstructorImpl)annotatedConstructorCache.get(constructor);
}
else
{
annConstructor = new AnnotatedConstructorImpl<>(webBeansContext, constructor, declaringClass);
AnnotatedConstructorImpl old = (AnnotatedConstructorImpl)annotatedConstructorCache.putIfAbsent(constructor, annConstructor);
if(old != null)
{
annConstructor = old;
}
}
return annConstructor;
}
/**
* Creates and configures new annotated field.
*
* @param declaring class
* @param field field instance
* @param declaringClass declaring class
* @return new annotated field
*/
@SuppressWarnings("unchecked")
public AnnotatedField newAnnotatedField(Field field, AnnotatedType declaringClass)
{
Asserts.assertNotNull(field, "field");
Asserts.assertNotNull(declaringClass, "declaringClass");
AnnotatedFieldImpl annotField;
if(annotatedFieldCache.containsKey(field))
{
annotField = (AnnotatedFieldImpl)annotatedFieldCache.get(field);
}
else
{
annotField = new AnnotatedFieldImpl<>(webBeansContext, field, declaringClass);
AnnotatedFieldImpl old = (AnnotatedFieldImpl) annotatedFieldCache.putIfAbsent(field, annotField);
if(old != null)
{
annotField = old;
}
}
return annotField;
}
/**
* Creates and configures new annotated method.
*
* @param declaring class
* @param method annotated method
* @param declaringType declaring class info
* @return new annotated method
*/
@SuppressWarnings("unchecked")
public AnnotatedMethod newAnnotatedMethod(Method method, AnnotatedType declaringType)
{
Asserts.assertNotNull(method, "method");
Asserts.assertNotNull(declaringType, "declaringType");
AnnotatedMethodImpl annotMethod;
if(annotatedMethodCache.containsKey(method))
{
annotMethod = (AnnotatedMethodImpl)annotatedMethodCache.get(method);
}
else
{
annotMethod = new AnnotatedMethodImpl<>(webBeansContext, method, declaringType);
AnnotatedMethodImpl old = (AnnotatedMethodImpl) annotatedMethodCache.putIfAbsent(method, annotMethod);
if(old != null)
{
annotMethod = old;
}
}
return annotMethod;
}
/**
* Returns the {@link AnnotatedMethod}s of the specified {@link AnnotatedType},
* filtering out the overridden methods.
*/
public Set> getFilteredAnnotatedMethods(AnnotatedType annotatedType)
{
Asserts.assertNotNull(annotatedType, "annotatedType");
Set> methods = annotatedMethodsOfTypeCache.get(annotatedType);
if (methods != null)
{
return cast(methods);
}
methods = Collections.unmodifiableSet(getFilteredMethods(annotatedType.getJavaClass(),
(Set)annotatedType.getMethods(),
new HashSet<>()));
Set> old = annotatedMethodsOfTypeCache.putIfAbsent(annotatedType, methods);
if (old != null)
{
return cast(old);
}
return cast(methods);
}
private Set> cast(Set> methods)
{
return (Set>)(Set>)methods;
}
/**
* Clear caches.
*/
public void clear()
{
modifiedAnnotatedTypeCache.clear();
annotatedTypeCache.clear();
annotatedConstructorCache.clear();
annotatedFieldCache.clear();
annotatedMethodCache.clear();
annotatedMethodsOfTypeCache.clear();
}
private Set extends AnnotatedMethod>> getFilteredMethods(Class> type, Set> allMethods, Set> filteredMethods)
{
if (type == null)
{
return filteredMethods;
}
for (AnnotatedMethod> annotatedMethod: allMethods)
{
if (annotatedMethod.getJavaMember().getDeclaringClass() == type && !isOverridden(annotatedMethod, filteredMethods))
{
filteredMethods.add(annotatedMethod);
}
}
return getFilteredMethods(type.getSuperclass(), allMethods, filteredMethods);
}
private boolean isOverridden(AnnotatedMethod> superclassMethod, Set> methods)
{
for (AnnotatedMethod> subclassMethod : methods)
{
if (ClassUtil.isOverridden(subclassMethod.getJavaMember(), superclassMethod.getJavaMember()))
{
return true;
}
}
return false;
}
private ConcurrentMap> getAnnotatedTypeCache(Class type)
{
ConcurrentMap> annotatedTypes = annotatedTypeCache.get(type);
if (annotatedTypes == null)
{
annotatedTypes = new ConcurrentHashMap<>();
ConcurrentMap> oldAnnotatedTypes = annotatedTypeCache.putIfAbsent(type, annotatedTypes);
if (oldAnnotatedTypes != null)
{
annotatedTypes = oldAnnotatedTypes;
}
}
return (ConcurrentMap>)(ConcurrentMap, ?>)annotatedTypes;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy