Eduardo Breijo created MYFACES-4138:
---------------------------------------

             Summary: Issue with some JSF Artifacts eligible for injection
                 Key: MYFACES-4138
                 URL: https://issues.apache.org/jira/browse/MYFACES-4138
             Project: MyFaces Core
          Issue Type: Bug
    Affects Versions: 2.3.0-beta, 2.2.12
            Reporter: Eduardo Breijo


When we register an ActionListener or PhaseListener globally via 
faces-config.xml, the instance that is created per listener is injectable, that 
is, we can do @Inject in the instance. These listeners are added to the 
injected bean storage list in the application map and as a result, we can call 
@PreDestroy and @PostConstruct on this scenario. 

On the other hand, when facelet elements <f:actionListener/> and 
<f:phaseListener/> are used, the instances that are created (per click for 
action listener or per view for phase listener) are not injectable. That is, we 
cannot do @Inject inside of these objects. And @PreDestroy and @PostConstruct 
are not invoked on them.

I supposes we want to have the same behavior in both cases.

To solve this issue, we can probably do a similar logic as what was done in 
FacesConfigurator that we call inject on the instance, and then store that in 
the injected bean storage list. We can add that logic in the 
ActionListenerHandler and PhaseListenerHandler classes after the instance is 
created.

// Code snippet
instance = (ActionListener) ReflectionUtil.forName(this.type).newInstance();
ExternalContext externalContext = faces.getExternalContext();

// Note that we have to make INJECTED_BEAN_STORAGE_KEY public
List<BeanEntry> injectedBeanStorage = 
(List<BeanEntry>)externalContext.getApplicationMap()                            
                         .get(FacesConfigurator.INJECTED_BEAN_STORAGE_KEY); 

InjectionProvider injectionProvider = 
InjectionProviderFactory.getInjectionProviderFactory(
                                                            
externalContext).getInjectionProvider(externalContext);

Object creationMetaData = injectionProvider.inject(instance);
injectedBeanStorage.add(new BeanEntry(instance, creationMetaData));
injectionProvider.postConstruct(instance, creationMetaData);

But there is an issue when adding that. Every time we use <f:actionListener/> 
with type defined but no binding, a new instance is created on every button 
click, the same will happen with <f:phaseListener/>. These instances are added 
to the list of injected bean storage, and that reference will exist until app 
shuts down, creating a memory leak. So we need a way to remove those references 
from the list once we are out of scope. We might need a different list for this 
case.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Reply via email to