I'm trying the get Bean class name without initialize the bean.
I need to know the class , I could get the bean from applicationContext and to check the class name from the bean instance, But I want to know the class with out actually creating/init the bean..
Is it possible ?
Object bean = applicationContext.getBean("beanName");
bean.getClass();
You can't do this after creating the ApplicationContext. Most ApplicationContext implementations will refresh() themselves and force instantiation of the beans.
What you can do is create a BeanFactoryPostProcessor in which you get the target bean definition and check the bean class.
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String className = beanFactory.getBeanDefinition("").getBeanClassName();
}
But note, as the javadoc for getBeanClassName() states
Hence, do not consider this to be the definitive bean type at runtime
but rather only use it for parsing purposes at the individual bean
definition level.
So use it with a grain of salt.
If you give us more details as to what you are trying to accomplish, there might be alternatives.
The code provided by Sotirious will not work for the beans that have parent beans and for the beans that are defined using Java Config or using #Component annotation (and similar annotatios like #Service, #Repository, #Component).
Just an extension which checks if it is AnnotatedBeanDefinition or if the bean has a parent:
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
String beanClassName = getBeanClassName(beanDefinitionName, beanFactory);
}
}
private String getBeanClassName(String beanName, ConfigurableListableBeanFactory beanFactory) {
String beanClassName;
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition instanceof AnnotatedBeanDefinition) {
AnnotationMetadata metadata = ((AnnotatedBeanDefinition) beanDefinition).getMetadata();
beanClassName = metadata.getClassName();
} else {
beanClassName = beanDefinition.getBeanClassName();
while (beanClassName == null) {
BeanDefinition parentBeanDefinition = beanFactory.getBeanDefinition(beanDefinition.getParentName());
beanClassName = parentBeanDefinition.getBeanClassName();
beanDefinition = parentBeanDefinition;
}
}
return beanClassName;
}
Note, this approach will not work in the case factory method is used. As Java Doc says:
Also, this may just be the class that a factory method is called on, or it may even be empty in case of a factory bean reference that a method is called on. Hence, do not consider this to be the definitive bean type at runtime but rather only use it for parsing purposes at the individual bean definition level.
Related
I'm trying to write a custom servlet (for AJAX/JSON) in which I would like to reference my #ManagedBeans by name. I'm hoping to map:
http://host/app/myBean/myProperty
to:
#ManagedBean(name="myBean")
public class MyBean {
public String getMyProperty();
}
Is it possible to load a bean by name from a regular servlet? Is there a JSF servlet or helper I could use for it?
I seem to be spoilt by Spring in which all this is too obvious.
In a servlet based artifact, such as #WebServlet, #WebFilter and #WebListener, you can grab a "plain vanilla" JSF #ManagedBean #RequestScoped by:
Bean bean = (Bean) request.getAttribute("beanName");
and #ManagedBean #SessionScoped by:
Bean bean = (Bean) request.getSession().getAttribute("beanName");
and #ManagedBean #ApplicationScoped by:
Bean bean = (Bean) getServletContext().getAttribute("beanName");
Note that this prerequires that the bean is already autocreated by JSF beforehand. Else these will return null. You'd then need to manually create the bean and use setAttribute("beanName", bean).
If you're able to use CDI #Named instead of the since JSF 2.3 deprecated #ManagedBean, then it's even more easy, particularly because you don't anymore need to manually create the beans:
#Inject
private Bean bean;
Note that this won't work when you're using #Named #ViewScoped because the bean can only be identified by JSF view state and that's only available when the FacesServlet has been invoked. So in a filter which runs before that, accessing an #Injected #ViewScoped will always throw ContextNotActiveException.
Only when you're inside #ManagedBean, then you can use #ManagedProperty:
#ManagedProperty("#{bean}")
private Bean bean;
Note that this doesn't work inside a #Named or #WebServlet or any other artifact. It really works inside #ManagedBean only.
If you're not inside a #ManagedBean, but the FacesContext is readily available (i.e. FacesContext#getCurrentInstance() doesn't return null), you can also use Application#evaluateExpressionGet():
FacesContext context = FacesContext.getCurrentInstance();
Bean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", Bean.class);
which can be convenienced as follows:
#SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
FacesContext context = FacesContext.getCurrentInstance();
return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}
and can be used as follows:
Bean bean = findBean("bean");
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?
I use the following method:
public static <T> T getBean(final String beanName, final Class<T> clazz) {
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(elContext, null, beanName);
}
This allows me to get the returned object in a typed manner.
Have you tried an approach like on this link? I'm not sure if createValueBinding() is still available but code like this should be accessible from a plain old Servlet. This does require to bean to already exist.
http://www.coderanch.com/t/211706/JSF/java/access-managed-bean-JSF-from
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
// May be deprecated
ValueBinding binding = app.createValueBinding("#{" + expr + "}");
Object value = binding.getValue(context);
You can get the managed bean by passing the name:
public static Object getBean(String beanName){
Object bean = null;
FacesContext fc = FacesContext.getCurrentInstance();
if(fc!=null){
ELContext elContext = fc.getELContext();
bean = elContext.getELResolver().getValue(elContext, null, beanName);
}
return bean;
}
I had same requirement.
I have used the below way to get it.
I had session scoped bean.
#ManagedBean(name="mb")
#SessionScopedpublic
class ManagedBean {
--------
}
I have used the below code in my servlet doPost() method.
ManagedBean mb = (ManagedBean) request.getSession().getAttribute("mb");
it solved my problem.
I use this:
public static <T> T getBean(Class<T> clazz) {
try {
String beanName = getBeanName(clazz);
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().evaluateExpressionGet(facesContext, "#{" + beanName + "}", clazz);
//return facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(), null, nomeBean);
} catch (Exception ex) {
return null;
}
}
public static <T> String getBeanName(Class<T> clazz) {
ManagedBean managedBean = clazz.getAnnotation(ManagedBean.class);
String beanName = managedBean.name();
if (StringHelper.isNullOrEmpty(beanName)) {
beanName = clazz.getSimpleName();
beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
}
return beanName;
}
And then call:
MyManageBean bean = getBean(MyManageBean.class);
This way you can refactor your code and track usages without problems.
I'm making a library to be used with Spring Boot. This lib define some annotations that can be used in methods.
How can I find (at runtime) the package of the application where the library is being used?
I need this in order to scan for the annotated methods.
You can implement BeanFactoryPostProcessor:
1. Using ConfigurableListableBeanFactory you can iterate over BeanDefinition
2. Determine if bean's class has your annotation
3. Get the package from the bean's class name
Example:
#Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Set<String> packages = findAnnotationUsagePackages(MyAnnotation.class, beanFactory);
...
}
private Set<String> findAnnotationUsagePackages(Class<? extends Annotation> annotationClass,
ConfigurableListableBeanFactory beanFactory) {
Set<String> annotationUsagePackages = new HashSet<>();
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
if (beanDefinition instanceof ScannedGenericBeanDefinition) {
ScannedGenericBeanDefinition genericBeanDefinition = (ScannedGenericBeanDefinition) beanDefinition;
if (AnnotationUtils.isCandidateClass(genericBeanDefinition.getBeanClass(), annotationClass)) {
String beanClassName = genericBeanDefinition.getBeanClassName();
if (beanClassName != null) {
annotationUsagePackages.add(ClassUtils.getPackageName(beanClassName));
}
}
}
}
return annotationUsagePackages;
}
}
About the AnnotationUtils.isCandidateClass():
Determine whether the given class is a candidate for carrying the specified annotation (at type, method or field level)
Also pay attention to the AbstractBeanDefinition.getBeanClass():
Throws: IllegalStateException - if the bean definition does not define a bean class, or a specified bean class name has not been resolved into an actual Class yet
P.S. also you can collect classes or meta-information inside AnnotationUtils.isCandidateClass condition block
I have the following class:
public class ServiceFactory {
private ServiceFactory() {
}
public static <T extends XXXX> T loadService(Class<T> klass) {
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
return applicationContext.getBean(klass);
}
}
It loads beans at runtime (I have a specific reason to do it like this).
I need to check if the bean is annotated with #Scope(BeanDefinition.SCOPE_PROTOTYPE) or just enforce it to be a prototype.
How would I do this?
First you need to find a bean name for your class. Then you may look for BeanDefinition using that name and get scope.
public <T> String findScope(ConfigurableApplicationContext applicationContext, Class<T> type) {
String[] names = applicationContext.getBeanFactory().getBeanNamesForType(type);
if(names.length != 1){
throw new IllegalArgumentException("Could not find bean of type" + type.getCanonicalName());
}
return applicationContext.getBeanFactory().getBeanDefinition(names[0]).getScope();
}
In Spring, if I define a prototype bean, I can inject it using lookup method injection at the current time of Spring Framework 4.3.0.RELEASE.
In Grails, how do I inject a prototype bean at runtime? Grails 2.5.4 docs show how to set bean.scope = 'prototype" and bean.singleton = false but does not actually give an example of how to inject a non-singleton bean.
I haven't seen much use of prototype-scope beans in Grails, and what I've seen uses the pattern described in the Spring docs that works directly with the ApplicationContext. I assume that you could use the same method injection approach in Grails that you use in Spring, but here's a simple factory class that doesn't involve CGLIB subclassing but is otherwise similar. It does retrieve a prototype instance from the ApplicationContext, but that's hidden in the implementation and doesn't clutter your application code:
package com.yourcompany
import groovy.transform.CompileStatic
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
#CompileStatic
class PrototypeFactory<T> implements ApplicationContextAware {
ApplicationContext applicationContext
final Class<T> beanClass
final String beanName
PrototypeFactory(Class<T> beanClass, String beanName) {
this.beanClass = beanClass
this.beanName = beanName
}
T getInstance() {
applicationContext.getBean(beanName, beanClass)
}
}
To use it, register a bean for the class, providing the bean name and bean class of the prototype bean (in resources.groovy, or in a plugin's doWithSpring):
beans = {
cartFactory(PrototypeFactory, ShoppingCart, 'shoppingCart')
}
Now you can inject the factory bean and call getInstance(), and it will return a new prototype instance, and since it's using generics you don't need any casts:
class SomeClass {
PrototypeFactory<ShoppingCart> cartFactory
...
def someMethod() {
ShoppingCart newCart = cartFactory.instance
...
}
}
You can reuse the factory class to register as many of these as you want for various prototype beans as long as they have unique bean names.
None of the names are significant, so change getInstance() to whatever you prefer, and change 'Factory' to 'Manager' or whatever.
I'd like to create an autowired bean in a Dao class in order to do logging opperations. My way was hitherto static final statement like this:
private static final Log log = LogFactory.getLog(LoggedClass.class);
But now I'm trying to use IoC to turn classes decoupled.
If just add configuration in pom.xml and try to do sth like
#Autowired
Log log;
I receive an error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'funciDaoImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.apache.commons.logging.Log br.com.bb.dirco.dao.impl.FunciDaoImpl.log; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'log' defined in class path resource [com/company/project/util/PersistenceConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.Class]: : No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
In order to get a logger, I had to provide a class to getLog method on LogFactory class and attribute it to Log instance. There's a way to do it using #Autowired Spring IoC? Thanks!
You can inject only those objects which are managed/created by Spring container. You have to register your bean (or factory method creating the bean) with container (with annotations like #Component/#Singleton/... or directly in xml)
In your case it's not very applicable since you have to have many different types (for every class) of logger objects provided by Spring and then when you inject they would have to be identified by different name/type for every class.
P.S. I don't see any problem using it the way you use it now
Where I work we have implemented support for #Autowired SLF4J Loggers using Springs BeanPostProcessor.
First you need to define an Logger placeholder bean in your application context. This bean is going to be injected by Spring into all bean with a #Autowired Logger field.
#Configuration
public class LoggerConfig {
#Bean
public Logger placeHolderLogger() {
return PlaceHolder.LOGGER;
}
#Bean
public AutowiredLoggerBeanPostProcessor loggerPostProcessor() {
return new AutowiredLoggerBeanPostProcessor();
}
}
Then you an AutowiredLoggerBeanPostProcessor which inspects all beans, indetify bean that contain Logger fields annotated with #Autowired (at this point should contain a reference to the Logger placeholder bean), create a new Logger for the partilcar bean an assigned it to the fields.
#Component
public class AutowiredLoggerBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
#Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
private void attachLogger(final Object bean) {
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
if (Logger.class.isAssignableFrom(field.getType()) &&
(field.isAnnotationPresent(Autowired.class) ||
field.isAnnotationPresent(Inject.class))) {
ReflectionUtils.makeAccessible(field);
if (field.get(bean) == PlaceHolder.LOGGER) {
field.set(bean, LoggerFactory.getLogger(bean.getClass()));
}
}
}
});
}
#Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}