Рендерер выбирается семейством компонентов, а не типом компонента, как вы, вероятно, ожидаете.
Давайте процитируем спецификацию JSF 2.0 :
3.1.2 Тип компонента
Хотя компонент UIComponent не является свойством, он является важной частью данных, связанных с каждым подклассом UIComponent
, что позволяет экземпляру Application
создавать новые экземпляры UIComponent
подклассы с этим типом.См. Раздел 7.1.11 «Фабрики объектов» для получения дополнительной информации о типе компонента.
3.1.3 Семейство компонентов
Каждый стандартный класс компонента пользовательского интерфейса имеет стандартное значение для семейства компонентов, котороеиспользуется для поиска средств визуализации, связанных с этим компонентом.Подклассы универсального класса UIComponent
обычно наследуют это свойство от своего суперкласса, так что средства визуализации, ожидающие только суперкласса, все еще смогут обрабатывать специализированные подклассы.
По сути, тип компонента является обязательнымдля JSF для создания компонента методом Application#createComponent()
.
UIComponent component = context.getApplication().createComponent("study.faces.Div");
Преимущество заключается в том, что компонент study.faces.Div
не зависит от времени компиляции и, следовательно, предлагает полиморфизм времени выполненияи возможности подключения (если вы знакомы с механизмом JDBC Class#forName()
и его фабриками , то вы лучше поймете эту часть).
Каждый тип компонента принадлежит к семейству, которое можетсостоят из одного или нескольких компонентов.Рендерер выбирается на основе семейства компонентов и типа рендерера: RenderKit#getRenderer()
Renderer renderer = context.getRenderKit().getRenderer(component.getFamily(), component.getRendererType());
Рендерер не выбран на основе типа компонента и типа рендерера,Это позволяет повторно использовать средство визуализации для нескольких типов компонентов, принадлежащих к семейству компонентов.В противном случае вам нужно будет зарегистрировать один рендерер для каждого отдельного компонента, даже если компоненты могут использовать один и тот же рендерер.
Следующая запись faces-config.xml
<component>
<component-type>study.faces.Div</component-type>
<component-class>javax.faces.component.UIPanel</component-class>
</component>
сообщает JSF, что Application
должен создавать экземпляр данного класса компонентов всякий раз, когда должен быть создан компонент данного типа компонента.Семейство компонентов там не указано, потому что оно уже неявно известно component.getFamily()
.
. И следующая faces-config.xml
запись
<render-kit>
<renderer>
<component-family>javax.faces.Panel</component-family>
<renderer-type>study.faces.DivRenderer</renderer-type>
<renderer-class>com.study.ui.DivRenderer</renderer-class>
</renderer>
</render-kit>
сообщает JSF, что RenderKit
должен вернутьсяэкземпляр данного класса визуализатора всякий раз, когда запрашивается визуализатор данного семейства компонентов и типа визуализатора.
Следующая .taglib.xml
запись
<tag>
<tag-name>div</tag-name>
<component>
<component-type>study.faces.Div</component-type>
<renderer-type>study.faces.DivRenderer</renderer-type>
</component>
</tag>
сообщает JSF (ну, Facelets)что данный тег должен создать компонент данного типа компонента в корне представления (класс которого был определен в faces-config.xml
), и что его тип рендерера должен быть установлен на данный тип рендерера.Обратите внимание, что тип компонента не используется для выбора средства визуализации, вместо этого он используется для создания компонента в корне представления.Также обратите внимание, что запись типа рендерера является необязательной.В противном случае будет использоваться собственный предопределенный тип рендерера компонента.Это позволяет повторно использовать существующие типы компонентов с другим типом рендерера.