Invoking listener for a subset of lifecycle methods in JSF

588 Views Asked by At

In a jsf bean which implements PhaseListener interface, the beforePhase and afterPhase methods will be invoked only before and after the phase that getPhaseId method indicates. This mechanism only enables us to select only one phase which these two methods will be called before and after.
Is there any way to tell JSF to call these two methods (beforePhase and afterPhase) on a subset (not just one) of lifecycle methods (

  1. Restore view
  2. Apply request values
  3. Process validations
  4. Update model values
  5. Invoke application
  6. Render response phase

)

public class HelloBean implements PhaseListener {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void afterPhase(PhaseEvent phaseEvent) {
        System.out.println("after phase "+phaseEvent.getPhaseId());
    }

    @Override
    public void beforePhase(PhaseEvent phaseEvent) {
        System.out.println("beforePhase "+phaseEvent.getPhaseId());
    }

    public void testMethod(){
        System.out.println("Test Method");
    }

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }
}
1

There are 1 best solutions below

1
Alex Fire On

Unfortunately this is not possible. As a generic work around you can implement a custom extended PhaseListener like this:

public interface MultiplePhasesListener extends PhaseListener {

    @Override
    default void beforePhase(PhaseEvent phaseEvent) {
        if (processPhase(phaseEvent.getPhaseId())) {
            beforePhases(phaseEvent);
        }
    }

    @Override
    default void afterPhase(PhaseEvent phaseEvent) {
        if (processPhase(phaseEvent.getPhaseId())) {
            afterPhases(phaseEvent);
        }
    }

    @Override
    default PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }

    default boolean processPhase(PhaseId phaseId) {
        if (phaseId == null) {
            return false;
        }
        List<PhaseId> phaseIds = getPhaseIds();
        if (phaseIds == null || phaseIds.isEmpty()) {
            return false;
        }
        return phaseIds.contains(phaseId);
    }

    void beforePhases(PhaseEvent phaseEvent);

    void afterPhases(PhaseEvent phaseEvent);

    List<PhaseId> getPhaseIds();
}

And use it like this:

public class MultiplePhasesListenerImpl implements MultiplePhasesListener {

    private static final long serialVersionUID = 1877176187821557447L;

    @Override
    public void beforePhases(PhaseEvent phaseEvent) {
        System.out.println(phaseEvent.getPhaseId());
    }

    @Override
    public void afterPhases(PhaseEvent phaseEvent) {
        System.out.println(phaseEvent.getPhaseId());
    }

    @Override
    public List<PhaseId> getPhaseIds() {
        return Arrays.asList(PhaseId.APPLY_REQUEST_VALUES, PhaseId.RENDER_RESPONSE);
    }
}  

Note that the PhaseListener methods are called before and after any phase but the logic is only processed before and after the desired phases.

Furthermore, note that the implementation of the MultiplePhasesListener interface uses default methods which are part of Java 8. If you use a lower Java version you could use an abstract class instead of an interface and extend your PhaseListener implementation of that abstract class. Disadvantage is that you can't extend from another class anymore.