How can I inject a dependency like #EJB, #PersistenceContext, #Inject, #AutoWired, etc in a #FacesConverter? In my specific case I need to inject an EJB via #EJB:
#FacesConverter
public class MyConverter implements Converter {
#EJB
protected MyService myService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// myService.doSomething
}
}
However, it didn't get injected and it remains null, resulting in NPEs. It seems that #PersistenceContext and #Inject also doesn't work.
How do I inject a service dependency in my converter so that I can access the DB?
Can I use #EJB to inject my service into a #FacesConverter?
No, not until JSF 2.3 is released. The JSF/CDI guys are working on that for JSF 2.3. See also JSF spec issue 1349 and this related "What's new in JSF 2.3?" article of my fellow Arjan Tijms. Only then dependency injection like #EJB, #PersistenceContext, #Inject, etc will work in a #FacesConverter when you explicitly add managed=true attribute to the annotation.
#FacesConverter(value="yourConverter", managed=true)
public class YourConverter implements Converter {
#Inject
private YourService service;
// ...
}
If not, what's the "correct" way to do this?
Before JSF 2.3, you have several options:
Make it a managed bean instead. You can make it a JSF, CDI or Spring managed bean via #ManagedBean, #Named or #Component. The below example makes it a JSF managed bean.
#ManagedBean
#RequestScoped
public class YourConverter implements Converter {
#EJB
private YourService service;
// ...
}
And the below example makes it a CDI managed bean.
#Named
#RequestScoped
public class YourConverter implements Converter {
#Inject
private YourService service;
// ...
}
Reference it as <h:inputXxx converter="#{yourConverter}"> instead of <h:inputXxx converter="yourConverter">, or as <f:converter binding="#{yourConverter}"> instead of <f:converter converterId="yourConverter">. Don't forget to remove the #FacesConverter annotation!
The disadvantage is that you cannot specify forClass and thus need to manually define the converter everywhere in the view where necessary.
Inject it in a regular managed bean instead.
#ManagedBean
#RequestScoped
public class YourBean {
#EJB
private YourService service;
// ...
}
And in your converter, grab or call it via EL.
YourBean yourBean = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);
// Then e.g. either
YourEntity yourEntity = yourBean.getService().findByStringId(value);
// Or
YourEntity yourEntity = yourBean.findEntityByStringId(value);
This way you can keep using #FacesConverter.
Manually grab the EJB from JNDI.
YourService yourService = (YourService) new InitialContext().lookup("java:global/appName/YourService");
The disadvantage is that there is a certain risk that this is not entirely portable. See also Inject EJB bean from JSF managed bean programmatically.
Install OmniFaces. Since version 1.6, it transparently adds support for #EJB (and #Inject) in a #FacesConverter without any further modification. See also the showcase. If you happen to need the converter for <f:selectItem(s)>, then the alternative is to use its SelectItemsConverter which will automatically perform the conversion job based on select items without the need for any database interaction.
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
See also Conversion Error setting value for 'null Converter'.
See also:
How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired
CDI Injection into a FacesConverter
Getting an #EJB in a #FacesValidator and #FacesConverter
The answer is Yes if you can accommodate Seam Faces module in your web application. Please check this post Injection of EntityManager or CDI Bean in FacesConverter. You can use #EJB in similar fashion.
You could access it indirectly through FacesContext, which is a parameter in both Converter methods.
The converter could be also annotated CDI Named with Application scope. When accessing the facade, two instances of the same class are used. One is the converter instance itself, dumb, without knowing EJB annotation. Another instance retains in application scope and could be accessed via the FacesContext. That instance is a Named object, thus it knows the EJB annotation. As everything is done in a single class, access could be kept protected.
See the following example:
#FacesConverter(forClass=Product.class)
#Named
#ApplicationScoped
public class ProductConverter implements Converter{
#EJB protected ProductFacade facade;
protected ProductFacade getFacadeFromConverter(FacesContext ctx){
if(facade==null){
facade = ((ProductConverter) ctx.getApplication()
.evaluateExpressionGet(ctx,"#{productConverter}",ProductConverter.class))
.facade;
}
return facade;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return getFacadeFromConverter(context).find(Long.parseLong(value));
}
...
#Inject will only works in CDI managed instances
This only works at least Java EE 7 and CDI 1.1 server:
#FacesConverter
public class MyConverter implements Converter {
protected MyService myService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
myService = CDI.current().select(MyService .class).get();
myService.doSomething();
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
https://stackoverflow.com/a/33017416/5626568
By Luis Chacon, Sv
Works fine, tested
definition EJB :
#Stateless
#LocalBean
public class RubroEJB {
#PersistenceContext(unitName = "xxxxx")
private EntityManager em;
public List<CfgRubroPres> getAllCfgRubroPres(){
List<CfgRubroPres> rubros = null;
Query q = em.createNamedQuery("xxxxxxx");
rubros = q.getResultList();
return rubros;
}
}
define bean with the Aplication bean scope, for get the EJB Object
#ManagedBean(name="cuentaPresService", eager = true)
#ApplicationScoped
public class CuentaPresService {
#EJB
private RubroEJB cfgCuentaEJB;
public RubroEJB getCfgCuentaEJB() {
return cfgCuentaEJB;
}
public void setCfgCuentaEJB(RubroEJB cfgCuentaEJB) {
this.cfgCuentaEJB = cfgCuentaEJB;
}
}
final Access to Ejb Object from Converter:
#FacesConverter("cuentaPresConverter")
public class CuentaPresConverter implements Converter {
#EJB
RubroEJB rubroEJB;
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
try {
CuentaPresService service = (CuentaPresService) fc.getExternalContext().getApplicationMap().get("cuentaPresService");
List<CfgCuentaPres> listCuentas=service.getCfgCuentaEJB().getAllCfgCuentaPres();
................
Related
I am new to jsf and using JSF 2.0 to keep user information in a session scoped bean. I need to access this information across other beans for grunt work. Presently, this is how i am doing:-
private UserBean myuser1 = (UserBean)FacesUtils.getManagedBean("UserBean");
and then access properties as
if (myuser1.getUserType == 1) ...
this works but some time throws Argument Error: parameter key is null exception. I have been using following method too:-
private UserBean myuser2 = new UserBean();
if (myuser2.getUserType == 1) ...
In second method, my understanding is that if UserBean is already created in session, it would be retried. There are lots of question about 'how to access one bean in another' so i am confused. Please tell me one clean method which should always work and not throw null pointer exception abruptly.
The simplest way I know of is using #ManagedProperty, I don't know what you mean by safest though.
Let's say this is your sessionScoped bean :
#ManagedBean
#SessionScopped
public class UserBean {
//bean attributes and methods
}
Then you can access it in any other bean (provided it has the same or a narrower scope) as an attribute like this :
#ManagedBean
#ViewScoped //in this cas you can use SessionScoped, FlowScoped, or RequestScoped too
public class AnotherBean {
#ManagedProperty("#{userBean}")
UserBean userB;
//rest of the bean
//be sure to add getters and setters for the injected bean
}
For more details check this
Hope this helps.
Actually,
parameter key is null exception: it's either you didn't initialize the object witch can be solver with either adding
object = new Object(); // in the constructor of the class.
The second problem may be that the object is " DETACHED " you need to call the object using the method merge (with the entity manager).
A detached object is a known value but the JPA system doesn't know if it is the latest version from the DB or even sometimes the id value is not set for some reason (Not managed with jpa in other words it can be your case).
If em is your entity manager and you have the following function:
public Object latestVersion(Object o){ em.merge; }
In your Bean with:
#EJB
Service service;
if you do em.latestVersion(o); the problem of detached object is solved.
And for the real answer:
To access a object from another view you can simply do the following.
#ManagedBean
#SessionScoped
..... Bean1 {
public static Object o;
.....
}
#ManagedBean
..... Bean 2 {
private Object b=Bean1.o;
.....
}
Good luck
The standard practice of setting dependency of a scoped bean in another scoped bean is to use #Inject annotation like
#Inject UserBean userBean; in the bean you want use the UserBean object.
Your UserBean should be a stateful one.
#Stateful
#LocalBean
public class UserBean
{
private String name;
public String getName() { return name; }
public void setName( String name_ ) { name = name_; }
}
And just inject it into a stateless bean to modify its state:
#Stateless
#LocalBean
public class MyStatelessBean
{
#EJB
private UserBean userBean;
public String getUserName() { userBean.getName(); };
public void setUserName( String name_ ) { userBean.setName( name_); }
}
Or you can access it from (not wider scoped) managed beans as well in the same way:
#ManagedBean
#Dependent
public class MyJSFManagedBean
{
#EJB
private UserBean userBean;
}
You wrote in your comment you does not use EJBs at all. The picture modify like this:
The UserBean should be a SessionScoped CDI bean
#Named
#SessionScoped
pubilc class UserBean
{}
The othe CDI bean should be in a nearer scope:
#Named
#Request // or #ViewScoped or #Dependent
public class OwnerBean
{
#Inject
UserBean userBean;
}
The container automatically takes care to create the beans in the right scope and insert them into the owers (any kind of container managed objects : servlets, filters, action listeners, JSF/CDI beans). You need to insert a wider scoped resource into a thinner scoped one.
How can I inject a dependency like #EJB, #PersistenceContext, #Inject, #AutoWired, etc in a #FacesConverter? In my specific case I need to inject an EJB via #EJB:
#FacesConverter
public class MyConverter implements Converter {
#EJB
protected MyService myService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// myService.doSomething
}
}
However, it didn't get injected and it remains null, resulting in NPEs. It seems that #PersistenceContext and #Inject also doesn't work.
How do I inject a service dependency in my converter so that I can access the DB?
Can I use #EJB to inject my service into a #FacesConverter?
No, not until JSF 2.3 is released. The JSF/CDI guys are working on that for JSF 2.3. See also JSF spec issue 1349 and this related "What's new in JSF 2.3?" article of my fellow Arjan Tijms. Only then dependency injection like #EJB, #PersistenceContext, #Inject, etc will work in a #FacesConverter when you explicitly add managed=true attribute to the annotation.
#FacesConverter(value="yourConverter", managed=true)
public class YourConverter implements Converter {
#Inject
private YourService service;
// ...
}
If not, what's the "correct" way to do this?
Before JSF 2.3, you have several options:
Make it a managed bean instead. You can make it a JSF, CDI or Spring managed bean via #ManagedBean, #Named or #Component. The below example makes it a JSF managed bean.
#ManagedBean
#RequestScoped
public class YourConverter implements Converter {
#EJB
private YourService service;
// ...
}
And the below example makes it a CDI managed bean.
#Named
#RequestScoped
public class YourConverter implements Converter {
#Inject
private YourService service;
// ...
}
Reference it as <h:inputXxx converter="#{yourConverter}"> instead of <h:inputXxx converter="yourConverter">, or as <f:converter binding="#{yourConverter}"> instead of <f:converter converterId="yourConverter">. Don't forget to remove the #FacesConverter annotation!
The disadvantage is that you cannot specify forClass and thus need to manually define the converter everywhere in the view where necessary.
Inject it in a regular managed bean instead.
#ManagedBean
#RequestScoped
public class YourBean {
#EJB
private YourService service;
// ...
}
And in your converter, grab or call it via EL.
YourBean yourBean = context.getApplication().evaluateExpressionGet(context, "#{yourBean}", YourBean.class);
// Then e.g. either
YourEntity yourEntity = yourBean.getService().findByStringId(value);
// Or
YourEntity yourEntity = yourBean.findEntityByStringId(value);
This way you can keep using #FacesConverter.
Manually grab the EJB from JNDI.
YourService yourService = (YourService) new InitialContext().lookup("java:global/appName/YourService");
The disadvantage is that there is a certain risk that this is not entirely portable. See also Inject EJB bean from JSF managed bean programmatically.
Install OmniFaces. Since version 1.6, it transparently adds support for #EJB (and #Inject) in a #FacesConverter without any further modification. See also the showcase. If you happen to need the converter for <f:selectItem(s)>, then the alternative is to use its SelectItemsConverter which will automatically perform the conversion job based on select items without the need for any database interaction.
<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
See also Conversion Error setting value for 'null Converter'.
See also:
How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired
CDI Injection into a FacesConverter
Getting an #EJB in a #FacesValidator and #FacesConverter
The answer is Yes if you can accommodate Seam Faces module in your web application. Please check this post Injection of EntityManager or CDI Bean in FacesConverter. You can use #EJB in similar fashion.
You could access it indirectly through FacesContext, which is a parameter in both Converter methods.
The converter could be also annotated CDI Named with Application scope. When accessing the facade, two instances of the same class are used. One is the converter instance itself, dumb, without knowing EJB annotation. Another instance retains in application scope and could be accessed via the FacesContext. That instance is a Named object, thus it knows the EJB annotation. As everything is done in a single class, access could be kept protected.
See the following example:
#FacesConverter(forClass=Product.class)
#Named
#ApplicationScoped
public class ProductConverter implements Converter{
#EJB protected ProductFacade facade;
protected ProductFacade getFacadeFromConverter(FacesContext ctx){
if(facade==null){
facade = ((ProductConverter) ctx.getApplication()
.evaluateExpressionGet(ctx,"#{productConverter}",ProductConverter.class))
.facade;
}
return facade;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return getFacadeFromConverter(context).find(Long.parseLong(value));
}
...
#Inject will only works in CDI managed instances
This only works at least Java EE 7 and CDI 1.1 server:
#FacesConverter
public class MyConverter implements Converter {
protected MyService myService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
myService = CDI.current().select(MyService .class).get();
myService.doSomething();
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
https://stackoverflow.com/a/33017416/5626568
By Luis Chacon, Sv
Works fine, tested
definition EJB :
#Stateless
#LocalBean
public class RubroEJB {
#PersistenceContext(unitName = "xxxxx")
private EntityManager em;
public List<CfgRubroPres> getAllCfgRubroPres(){
List<CfgRubroPres> rubros = null;
Query q = em.createNamedQuery("xxxxxxx");
rubros = q.getResultList();
return rubros;
}
}
define bean with the Aplication bean scope, for get the EJB Object
#ManagedBean(name="cuentaPresService", eager = true)
#ApplicationScoped
public class CuentaPresService {
#EJB
private RubroEJB cfgCuentaEJB;
public RubroEJB getCfgCuentaEJB() {
return cfgCuentaEJB;
}
public void setCfgCuentaEJB(RubroEJB cfgCuentaEJB) {
this.cfgCuentaEJB = cfgCuentaEJB;
}
}
final Access to Ejb Object from Converter:
#FacesConverter("cuentaPresConverter")
public class CuentaPresConverter implements Converter {
#EJB
RubroEJB rubroEJB;
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
try {
CuentaPresService service = (CuentaPresService) fc.getExternalContext().getApplicationMap().get("cuentaPresService");
List<CfgCuentaPres> listCuentas=service.getCfgCuentaEJB().getAllCfgCuentaPres();
................
I have a stateful, session scoped (CDI) EJB that holds the info about the user session.
#Stateful
#SessionScoped
public class GestorSesion implements IGestorSesionLocal, Serializable {
private final static long serialVersionUID = 1L;
private static final Logger log = Logger.getLogger(GestorSesion.class.getName());
#PostConstruct
private void init() {
log.info("Configurando información de usuario");
log.info("****************************************************************************");
}
#Override
public void cerrarSesion() {
}
#Override
public ISessionInfo getSesionInfo() {
return null;
}
}
Now, I want to call cerrarSesion() (closeSession()) from an HttpSessionListener
public class GestorSesionWeb implements HttpSessionListener {
private static final Logger log = Logger.getLogger(GestorSesionWeb.class.getName());
#Inject
private Instance<IGestorSesionLocal> gestorSesion;
#Override
public void sessionCreated(HttpSessionEvent se) {
if (log.isLoggable(Level.FINE)) {
log.fine("Iniciada sesión web");
}
gestorSesion.get().getSesionInfo();
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
if (log.isLoggable(Level.FINE)) {
log.fine("Limpiando sesión al salir");
}
try {
this.gestorSesion.get().cerrarSesion();
if (log.isLoggable(Level.FINE)) {
log.fine("Sesión limpiada sin problemas");
}
} catch (Exception e) {
log.log(Level.WARNING, "Excepción limpiando sesión", e);
}
}
}
And I access the EJB from the webapp, directly (injecting using #EJB) into the beans that I use for JSF (they are also CDI managed beans).
The issue that I face is that it seems that the HttpSessionListener seems to be in a different "session scope" than the JSF beans. Two instances of GestorSession are created; one instantiated from the JSF and other instantiated from the HttpSessionListener.
I have tried injecting the bean via #Inject Instance<IGestorSesionLocal>, #Inject IGestorSesionLocal and BeanManager, with identical results.
This bug report suggests that it should to work correctly (the bug is solved for my version), but I still cannot get around it. I have looked around, but what I find are Q&A relating to JSF managed beans (yes, I could try to wrap a reference to the EJB in a JSF managed bean, but I would like to try it "correctly" first).
Working with WilFly 8.1.0 and JDK 7
Any ideas?
I think your pb comes from here:
And I access the EJB from the webapp, directly (injecting using
#EJB) into the JSF beans.
When use CDI with EJB (by putting a #Sessionscoped on it for instance) you got an CDI bean that also has an EJB nature but not the other way around. In other word CDI is aware of the EJB nature but EJB is not aware of CDI.
So if you want to inject an EJB as a CDI bean in your code use #Inject and not #EJB. From Java EE 6 the admitted good practice is to always use #Inject except for EJB remote.
Also be sure to only use CDI managed bean and not a mix of CDI and JSF managed bean.
Is the post construct annotation not supported in validators?
I have a application scoped jndi servicelocator bean which I inject as a managed property into my validator.
#ManagedProperty(value = "#{jndiServiceLocatorBean}")
private final JndiServiceLocatorBean jndiServiceLocatorBean = null;
The post construct annotated method to initialize my necessary remote bean is never invoked and so my remote bean remains null.
private UserBeanRemote userBeanRemote = null;
#PostConstruct
public void postConstruct()
{
this.userBeanRemote = (UserBeanRemote) this.jndiServiceLocatorBean.getRemoteBean(UserBeanRemote.class);
}
It works only if the Validator is annotated as a #ManagedBean or #Named instead of #FacesValidator.
Just use the normal constructor instead.
#FacesValidator("fooValidator")
public class FooValidator implements Validator {
private UserBeanRemote userBeanRemote;
public FooValidator() {
FacesContext context = FacesContext.getCurrentInstance();
JndiServiceLocatorBean jndiServiceLocatorBean = context.getApplication().evaluateExpressionGet(context, "#{jndiServiceLocatorBean}", JndiServiceLocatorBean.class);
this.userBeanRemote = (UserBeanRemote) jndiServiceLocatorBean.getRemoteBean(UserBeanRemote.class);
}
// ...
}
Support for dependency injection in JSF artifacts other than #ManagedBean is planned for JSF 2.2 (spec issue 763).
See also:
How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired
Communication in JSF 2.0 - Getting an EJB in #FacesValidator and #FacesConverter
Ok here is my session bean. I can always retrieve the currentUser from any Servlet or Filter. That's not the problem The problem is the fileList, and currentFile. I've tested with simple int's and Strings and its' the same effect. If I set a value from my view scoped bean I can get the data from another class.
#ManagedBean(name = "userSessionBean")
#SessionScoped
public class UserSessionBean implements Serializable, HttpSessionBindingListener {
final Logger logger = LoggerFactory.getLogger(UserSessionBean.class);
#Inject
private User currentUser;
#EJB
UserService userService;
private List<File> fileList;
private File currentFile;
public UserSessionBean() {
fileList = new ArrayList<File>();
currentFile = new File("");
}
#PostConstruct
public void onLoad() {
Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
String email = principal.getName();
if (email != null) {
currentUser = userService.findUserbyEmail(email);
} else {
logger.error("Couldn't find user information from login!");
}
}
Here is an example.
My view scoped bean. This is how it is decorated.
#ManagedBean
#ViewScoped
public class ViewLines implements Serializable {
#Inject
private UserSessionBean userSessionBean;
Now the code.
userSessionBean.setCurrentFile(file);
System.out.println("UserSessionBean : " + userSessionBean.getCurrentFile().getName());
I can see the current file name perfectly. This is actually being printed from a jsf action method. So obviously the currentFile is being set.
Now if I do this.
#WebFilter(value = "/Download")
public class FileFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpSession session = ((HttpServletRequest) request).getSession(false);
UserSessionBean userSessionBean = (UserSessionBean) session.getAttribute("userSessionBean");
System.out.println(userSessionBean.getCurrentUser().getUserId()); //works
System.out.println("File filter" + userSessionBean.getCurrentFile().getName()); //doesn't work
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
currentUser shows up fine but I can't see the file. It's just blank. The same thing happens with Strings, int's, etc.
Thanks for any help you can provide on this.
INFO: UserSessionBean : Line 3B--8531268875812004316.csv (value printed from view scoped bean)
INFO: File filter tester.csv (value printed when filter is ran.)
**EDIT**
This worked.
FacesContext context = FacesContext.getCurrentInstance();
userSessionBean = (UserSessionBean) context.getApplication().evaluateExpressionGet(context, "#{userSessionBean}", UserSessionBean.class);
I put this in the constructor of the ViewScoped and everything was fine. Now why isn't the inject doing what I thought? At first I thought maybe because I was using JSF managed beans instead of the new CDI beans. But I changed the beans to the new style(with named) and that was the same effect.
Does the inject only allow you to access the beans but not change their attributes?
You're mixing JSF and CDI. Your UserSessionBean is a JSF #ManagedBean, yet you're using CDI #Inject to inject it in another bean. CDI doesn't reuse the JSF managed one, it instead creates a brand new one. Use the one or the other, not both. The correct annotation to inject a JSF-managed bean is #ManagedProperty.
Replace
#Inject
private UserSessionBean userSessionBean;
by
#ManagedProperty(value="#{userSessionBean}")
private UserSessionBean userSessionBean;
and ensure that you don't have a import javax.enterprise.context anywhere in your code (which is the package of CDI annotations).
Alternatively, migrate all JSF bean management annotations to CDI bean management annotations.
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
#Named
#SessionScoped
public class UserSessionBean implements Serializable {}
import javax.inject.Named;
import javax.faces.view.ViewScoped;
#Named
#ViewScoped
public class ViewLines implements Serializable {}
Additional advantage is that you can just #Inject it inside a regular servlet or filter without the need to manually grab it as request/session/application attribute.
Moreover, JSF bean management annotations are deprecated since JSF 2.3. See also Backing beans (#ManagedBean) or CDI Beans (#Named)?
My best GUESS as to why this is happening, is because the variable file, is being set in view scope, and then passed by reference into the session scoped bean. Maybe this is happening because when the view scope bean is destroyed, it still has a reference to that variable, but doesn't bother to see if there's any other references to it in session scope, where it should be preserved. Hence, when it's destroyed, it's removed from both view and session scope in this case.
Could you try calling setCurrentFile with an object instantiated with 'new'? That might prove or disprove this hypothesis of mine.
Otherwise, my best advice would be to crack open the debugger, and see exactly where getCurrentFile is being changed.