Search code examples
jsfcdimanaged-property

Conditional injection of bean with ManagedProperty


I have a controller with the following properties:

@ManagedProperty(value="#{remoteApplication}")
private transient ProcessService applicationService;

@ManagedProperty(value="#{remoteSystem}")
private transient SystemService systemService;

@ManagedProperty(value="#{remoteFileSystem}")
private transient FileSystemService fileSystemService;

I would like to inject beans conditionally, according to a property file telling if the services shall be local or remote.

Example provided hereabove is for remote, and for local, would be:

@ManagedProperty(value="#{localApplication}")
private transient ProcessService applicationService;

@ManagedProperty(value="#{localSystem}")
private transient SystemService systemService;

@ManagedProperty(value="#{localFileSystem}")
private transient FileSystemService fileSystemService;

Is there any way to do this with JSF (maybe using ValueExpression as specified in ManagedProperty documentation) ? Or do I have to use CDI ?

Many thanks in advance for your suggestions!

Kind regards,

Zim


Solution

  • You can do it with just JSF, even a CDI integration could help you dividing it in proper layers. Take a look at this JSF solution, using an application scoped bean which manages the configuration. The scope of the Bean can be anyone you need. Being your Service classes @ManagedBean:

    @ManagedBean
    @ApplicationScoped
    public class LocalProcessService implements ProcessService {
    
        public LocalProcessService() {
            System.out.println("Local service created");
        }
    
    }
    
    @ManagedBean
    @ApplicationScoped
    public class RemoteProcessService implements ProcessService {
    
        public RemoteProcessService() {
            System.out.println("Remote service created");
        }
    
    }
    

    Then, implement a Configuration Bean which reads the file you want and stores a flag with the read value. I use a Random function for testing purpose:

    @ManagedBean(eager = true)
    @ApplicationScoped
    public class PropertiesBean {
    
        private boolean localConfig = false;
    
        public PropertiesBean() {
            // Read your config file here and determine wether it is local
            //or remote configuration
            if (new Random().nextInt(2) == 1) {
                localConfig = true;
            }
        }
    
        public boolean isLocalConfig() {
            return localConfig;
        }
    
    }
    

    Once you've got it, in your view controller make the injection depending on that flag value, using a ternary operator:

    @ManagedBean
    @ViewScoped
    public class Bean {
    
        @ManagedProperty(value = "#{propertiesBean.localConfig ? localProcessService : remoteProcessService}")
        protected ProcessService processService;
    
        public void setProcessService(ProcessService processService) {
            this.processService = processService;
        }
    
    }
    

    Alternativelly, you could store the service reference directly in your PropertiesBean, in order not to have to evaluate that flag value in your managed beans. Just evaluate the EL expression you need into the context (see the reference).

    See also: