Я не могу подробно объяснить конкретную проблему, но я могу только наблюдать и подтверждать, что подход, показанный в вопросе, неуклюж и тесно связан с Мохаррой.Есть com.sun.faces.*
конкретные зависимости, требующие Мохарры.Этот подход не использует стандартные методы API и, кроме того, не будет работать в других реализациях JSF, таких как MyFaces.
Вот гораздо более простой подход, использующий стандартные методы, предоставляемые API.Ключевым моментом является то, что вы должны использовать FaceletContext#includeFacelet()
для включения ресурса составного компонента в заданный родительский элемент.
public static void includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id) {
// Prepare.
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
// This basically creates <ui:component> based on <composite:interface>.
Resource resource = application.getResourceHandler().createResource(resourceName, libraryName);
UIComponent composite = application.createComponent(context, resource);
composite.setId(id); // Mandatory for the case composite is part of UIForm! Otherwise JSF can't find inputs.
// This basically creates <composite:implementation>.
UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE);
implementation.setRendererType("javax.faces.Group");
composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation);
// Now include the composite component file in the given parent.
parent.getChildren().add(composite);
parent.pushComponentToEL(context, composite); // This makes #{cc} available.
try {
faceletContext.includeFacelet(implementation, resource.getURL());
} catch (IOException e) {
throw new FacesException(e);
} finally {
parent.popComponentFromEL(context);
}
}
Представьте, что вы хотите включить <my:testComposite id="someId">
из URI xmlns:my="http://java.sun.com/jsf/composite/mycomponents"
, затем используйте его следующим образом:
includeCompositeComponent(parent, "mycomponents", "testComposite.xhtml", "someId");
Это также было добавлено в библиотеку утилит JSF OmniFaces как Components#includeCompositeComponent()
(начиная с V1.5).
Обновление , начиная с JSF 2.2, класс ViewDeclarationLanguage
получил новый метод createComponent()
, принимающий URI и имя тега taglib, которые также могут использоваться для этой цели.Итак, если вы используете JSF 2.2, подход должен быть выполнен следующим образом:
public static void includeCompositeComponent(UIComponent parent, String taglibURI, String tagName, String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIComponent composite = context.getApplication().getViewHandler()
.getViewDeclarationLanguage(context, context.getViewRoot().getViewId())
.createComponent(context, taglibURI, tagName, null);
composite.setId(id);
parent.getChildren().add(composite);
}
Представьте, что вы хотите включить <my:testComposite id="someId">
из URI xmlns:my="http://xmlns.jcp.org/jsf/composite/mycomponents"
, затем используйте его следующим образом:
includeCompositeComponent(parent, "http://xmlns.jcp.org/jsf/composite/mycomponents", "testComposite", "someId");