2015-06-09 2 views
0

Я пытаюсь написать специальный компонент JSF , который динамически выбирает создает и отображает существующий составной компонент . Пока что все работает нормально, за исключением передачи атрибутов композиту.JSF 2.2 ViewDeclarationLanguage createComponent передает атрибуты как String?

Это мой пользовательский класс компонентов (обработка ошибок и т.д. раздели для более удобного чтения):

@FacesComponent(createTag = true) 
public class ChooseEZComp extends UIComponentBase { 

    @Override 
    public void encodeBegin(FacesContext context) throws IOException { 
    Object value = getAttributes().get("value"); 

    String ezCompName = value.getClass().getSimpleName().toLowerCase(); 
    // ezCompName is something like "freelink" or "treenode" 

    Map<String, Object> params = new HashMap<>(); 
    params.put("node", value); 
    // log.debug(params.get("node").getClass().getName()) -> yields correct class name 

    ViewDeclarationLanguage viewDeclarationLanguage = context 
     .getApplication() 
     .getViewHandler() 
     .getViewDeclarationLanguage(context, context.getViewRoot().getViewId()); 

    UIComponent component = viewDeclarationLanguage 
     .createComponent(context, 
     "http://xmlns.jcp.org/jsf/composite/ezcomp", 
     ezCompName, 
     params); 

    component.encodeAll(context); 
    } 
} 

Составной компонент (у меня есть несколько из них), который получает выбрали и оказываемых этим классом:

<cc:interface> 
    <cc:attribute name="node" required="true"/> 
    </cc:interface> 

    <cc:implementation> 
    <h:outputText value="The class of node is: #{cc.attrs.node.class.name}"/> 
    </cc:implementation> 

Это, как я использую тег в моей странице JSF:

<test:chooseEZComp value="#{treeView.selectedNode.data}"/> 

Так «VALU e "всегда гарантируется не типа java.lang.String (это некоторый JPA @Entity).

Но все-таки выходной результат на странице JSF всегда:

Класс узла: java.lang.String

Где я неправ? Невозможно передать что-то отличное от String в качестве параметра в композит?

Я runnind wildfly-8.2.0-финал с Java EE 7 (и Primefaces 5, но которая не используется здесь)

Любые намеки приветствуются!


Edit: я, конечно, тоже пытался заставить тип атрибута в куб.см: интерфейс

<cc:interface> 
    <cc:attribute name="node" required="true" type="some.package.type"/> 
</cc:interface> 

Но это как следствие привело к IllegalArgument Exception:

IllegalArgumentException: Невозможно преобразовать ... типа класса java.lang.String в класс

ответ

0

Оказывается, я неправильно понял API ... Карта < String, Object > в подписи заставила меня подумать, что я могу передать объект. Но Javadoc точнее об этом:

атрибуты - любое имя = значение пары, которые в противном случае были бы приведены на разметке, что вызвало бы создание этого компонента [..]

Таким образом, вы не передать значение в createComponent, а скорее выражение, которое было используется для вычисления значения для указанного атрибута или имущественном имя:

Map<String, Object> attributes = new HashMap<>(); 
    ValueExpression valueExpression = getValueExpression("value"); 
    attributes.put("node", valueExpression.getExpressionString()); 

Комизм прочитайте: , чтобы найти решение, которое я отлаживал через jsf-imp-2.2.8-jbossorg и наткнулся на код для создания компонента. В основном то, что он делает:

  • создать JSF файл Xhtml в временную папку и использовать OutputStreamWriter # присоединять написать страницу JSF ровно с одним тегом в ней (тот, который вы хотите создать)
  • петли через все атрибуты и записывать их как attribues в тег
  • Сохранить файл и кормить его к DefaultFaceletFactory # createFacelet
  • создать контейнер именования и сделать его родитель сгенерированного facelet (применяется)
  • использования FindComponent на T он называет контейнер для получения созданного тега и возвращает его

По крайней мере, после обнаружения этого ясно, почему вам нужно передать выражение значения, а не само значение.