2

I have a JSF project, where I use OmniFaces to enable an @EJB injection in a @FacesConverter. With the code from the showcase, it worked out well.

But I wand to understand a bit more, what is happening under the surface and I expected some import from OmniFaces in the converter, but there are just imports from javax.faces.*

Why is there no OmniFaces import necessary and how is the framework told to use the ConverterManager? Is it just by adding the OmniFaces libraries to the buildpath?

Sorry, if this is a stupid question. Thanks for any explanation.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
bauz
  • 125
  • 1
  • 12

1 Answers1

3

Converter instances are under the covers created via Application#createConverter().

Converter converter = facesContext.getApplication().createConverter(idOrClass);

Like as many abstract artifacts in JSF API, the Application follows the decorator (wrapper) pattern, like as you can find over all place in java.io.*. You can provide a custom one via a <factory> in faces-config.xml as OmniFaces did below in its /META-INF/faces-config.xml:

<factory>
    <application-factory>org.omnifaces.application.OmniApplicationFactory</application-factory>
</factory>

The application factory implementation boils down to this:

public class OmniApplicationFactory extends ApplicationFactory {

    private final ApplicationFactory wrapped;

    public OmniApplicationFactory(ApplicationFactory wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public Application getApplication() {
        return new OmniApplication(wrapped.getApplication());
    }

    @Override
    public void setApplication(Application application) {
        wrapped.setApplication(application);
    }

    @Override
    public ApplicationFactory getWrapped() {
        return wrapped;
    }

}

(The actual implementation is a little bit more convoluted to work around broken application factories coming from older versions of 3rd party libraries such as Seam, Weld and Spring WebFlow (which are already for long fixed on their side by the way)).

The OmniApplication implementation boils down to this:

public class OmniApplication extends ApplicationWrapper {

    private final Application wrapped;
    private final ConverterManager converterManager;

    public OmniApplication(Application wrapped) {
        this.wrapped = wrapped;
        converterManager = BeanManager.INSTANCE.getReference(ConverterManager.class);
    }

    @Override
    public Converter createConverter(String converterId) {
        Converter converter = converterManager.createConverter(getWrapped(), converterId);
        return (converter != null) ? converter : super.createConverter(converterId);
    }

    @Override
    public Application getWrapped() {
        return wrapped;
    }

}

You see, there the delegation to ConverterManager is happening.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555