Привязка компонента JSF без ошибки преобразования свойства bean

В столбце таблицы я попытался связать значение компонента с локальной переменной EL, а затем использовать эту переменную в качестве параметра:

        <h:column>
            <h:outputLabel value="Enter a quantity to put into the cart" for="qty"/>
            <h:inputText id="qty" binding="#{qty}" converter="javax.faces.Number"/>
        </h:column>
        <h:column>
            <h:commandButton value="Put into cart" type="submit"
                             action="#{shoppingCart.addToCart(product, qty)}"/>
        </h:column>

Где product — текущий элемент таблицы данных (список отфильтрованных или неотфильтрованных товаров, которых нет в корзине).

Теперь при попытке добавить товар в корзину (например, с количеством 12) возникает следующее исключение:

javax.faces.el.EvaluationException: java.lang.IllegalArgumentException: Cannot convert javax.faces.component.html.HtmlInputText@377c8b02 of type class javax.faces.component.html.HtmlInputText to class java.lang.Integer
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at javax.faces.component.UIData.broadcast(UIData.java:1108)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
at java.lang.Thread.run(Thread.java:745)

Я использую Glassfish 4.1.1 с JSF версии 2.2.12.

буду благодарен за любые идеи

ПОЯСНЕНИЕ

Как указал BalusC в этом вопросе привязка компонента JSF без свойства компонента и других, binding="#{var}" на самом деле является действительным XHTML. Таким образом, не требуется никакого вспомогательного компонента, а объявленная переменная находится в области запроса. Я нахожу этот вариант более элегантным и, следовательно, хотел бы придерживаться его.


person Wecherowski    schedule 16.09.2016    source источник
comment
Почему вы считаете преимуществом то, что для этого вам не нужен поддерживающий компонент? На самом деле, я не могу себе представить, что у вас нет класса «продукт» в корзине для покупок с полем-членом «количество» или подобным, поэтому «поддерживающий компонент» уже есть.   -  person Kukeltje    schedule 16.09.2016
comment
Я сделал поправку. На самом деле речь идет о создании нового объекта ShoppingCartItem. Извините за двусмысленный вопрос   -  person Wecherowski    schedule 16.09.2016


Ответы (3)


Вместо binding="#{qty}" (который следует использовать для привязки вашего компонента ввода к экземпляру Java вашего компонента в управляемом компоненте) используйте: value="#{shoppingCart.quantityAsInteger}", или, если вы работаете со списком элементов корзины покупок: value="#{shoppingCartItem.quantityAsInteger}".

Помимо правильной привязки значения, это также даст вам преимущество наличия количества как части вашей модели. Кроме того, когда value привязан к Integer, нет необходимости добавлять преобразователь. JSF позаботится о преобразовании Integer (и некоторых других типах) по умолчанию. .

Итак, убедитесь, что у вас есть управляемый компонент, содержащий количество или список элементов корзины, каждый из которых имеет количество. В случае списка элементов корзины вы получите что-то вроде:

ShoppingCart.java

// You will probably already have something like this for your table
private List<ShoppingCartItem> shoppingCartItems;

ShoppingCartItem.java

// Quantity used for binding (add getter and setter).
private Integer quantity;

private Product product;

XHTML

<h:column>
    <h:outputLabel value="Enter a quantity to put into the cart" for="qty"/>
    <h:inputText id="qty" binding="#{shoppingCartItem.quantity}" />
</h:column>
person Jasper de Vries    schedule 16.09.2016
comment
Спасибо :) Я не могу использовать binding=#{shoppingCartItem.quantity}, так как в данный момент товара нет. Я имею в виду, что объект создается только после нажатия кнопки commandButton, и поэтому я не могу указать значение для элемента еще до его создания. Или я вас неправильно понимаю? - person Wecherowski; 16.09.2016
comment
К сожалению, вы можете добавить целое число к Product для добавления продукта. Суть вашей проблемы, как вы уже выяснили, заключается в том, что вы должны использовать value для привязки значений. - person Jasper de Vries; 16.09.2016
comment
В этом случае используйте value="#{product.quantity}" и action="#{shoppingCart.addToCart(product)}" - person Jasper de Vries; 16.09.2016

Попробуйте использовать атрибут value вместо атрибута binding в h:inputText и используйте атрибут binding для компонента таблицы. Таким образом, вы можете получить доступ к выбранной (нажатой) строке в методе действия: если атрибут binding таблицы имеет значение #{bean.dataTable}, вы можете получить данные строки в методе, подобном getDataTable.getRowData().

person peterremec    schedule 16.09.2016

Хотя объявление переменной EL является допустимым XHTML, сам компонент привязан к переменной, если используется атрибут binding. При использовании переменной EL с атрибутом value не возникают ошибки преобразования, например:

        <h:inputText id="qty" value="#{qty}" converter="javax.faces.Number"/>
        ....
        <h:commandButton value="Put into cart" type="submit"
                         action="#{shoppingCart.addToCart(product, qty)}"/>
person Wecherowski    schedule 16.09.2016
comment
Это я тебе и говорил ;-) - person Jasper de Vries; 16.09.2016
comment
@JasperdeVries: не совсем ... здесь он определяет переменную requestScoped, которая не является полем в bean-компоненте. Он существует только во время запроса. Немного отличается от вашего примера. Также см. его «редактирование/разъяснение» к вопросу - person Kukeltje; 16.09.2016
comment
Хорошо.. теперь я понял. Я думал, что речь идет о редактировании корзины! - person Jasper de Vries; 16.09.2016
comment
Я также думаю, что речь идет о редактировании корзины. Но отредактировать его необычным образом с помощью «оптимизации», которая не является оптимизацией... - person Kukeltje; 16.09.2016