jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] Re: [jsr372-experts mirror] Re: [URGENT] @FacesDataModel inconsistencies with the spec (Re: Get your remaining items in)

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Tue, 14 Feb 2017 18:03:40 -0500

Hi

Yes, the trick clarifies my doubts about it. It is not pretty, but it will
work. Thanks for mention it.

regards,

Leonardo Uribe

2017-02-14 17:25 GMT-05:00 arjan tijms <arjan.tijms_at_gmail.com>:

> p.s. the utility/trick method I mentioned earlier is this one:
>
>
> @SuppressWarnings("unchecked")
> public <T> DataModel<T> createDataModel(Class<T> forClass, Object
> value) {
> class LocalUIData extends UIData {
> @Override
> public DataModel<?> getDataModel() {
> return super.getDataModel();
> }
> }
> LocalUIData localUIData = new LocalUIData();
> localUIData.setValue(value);
>
> return (DataModel<T>) localUIData.getDataModel();
> }
>
>
> That one implements the required lookup without having to know the details
> of the Bean discovery and type resolution algorithms.
>
> E.g.
>
> Given:
>
> public class Child1 {
>
> }
>
> and
>
> package test.jsf23;
>
> @FacesDataModel(forClass = Child1.class)
> public class Child1Model<E> extends DataModel<E> {
>
> @Override
> public int getRowCount() {
> return 0;
> }
>
> @Override
> public E getRowData() {
> return null;
> }
>
> @Override
> public int getRowIndex() {
> return 0;
> }
>
> @Override
> public Object getWrappedData() {
> return null;
> }
>
> @Override
> public boolean isRowAvailable() {
> return false;
> }
>
> @Override
> public void setRowIndex(int arg0) {
> }
>
> @Override
> public void setWrappedData(Object arg0) {
> }
>
> }
>
>
> Then the following must work:
>
> DataModel<Child1> myModel = createDataModel(Child1.class, new Child1());
> System.out.println(myModel.getClass());
>
> The result printed will be:
>
> "class test.jsf23.Child1Model"
>
> Hope this clarifies things.
>
> Kind regards,
> Arjan Tijms
>
>
>
>
>
>
>
>
>
>
>
>
>
> On Tue, Feb 14, 2017 at 8:59 PM, Leonardo Uribe <leonardo.uribe_at_irian.at>
> wrote:
>
>> Hi
>>
>> AT> But I'm afraid it's, unfortunately, simply too late now.
>>
>> @Ed, Manfred: WDYT? a public review where you send feedback before 30
>> days and is it too late? why bother to send a public review if changes will
>> not be accepted?
>>
>> regards,
>>
>> Leonardo Uribe
>>
>>
>> 2017-02-14 14:14 GMT-05:00 arjan tijms <arjan.tijms_at_gmail.com>:
>>
>>> Hi,
>>>
>>> On Tuesday, February 14, 2017, Leonardo Uribe <leonardo.uribe_at_irian.at>
>>> wrote:
>>>
>>>> Hi
>>>>
>>>> The problem here is there are other components that does not extend
>>>> from UIData and uses DataModel.
>>>>
>>>
>>> I'm absolutely aware of the necessity and the use case ;)
>>>
>>> But in my example the component that needs the DataModel instance
>>> doesn't have to extend from UIData. Using the trick I mentioned you can
>>> instantiate a separate UIData instance, then do the setValue/getDataModel
>>> trick on it.
>>>
>>>
>>>> The closest example is UIRepeat, but there are others too.
>>>>
>>>
>>> UIRepeat should already support it as well, but the issue is of course
>>> components from third party libraries that don't extend from either UIData
>>> or UIRepeat.
>>>
>>> Those can use the trick I mentioned though. Not ideal I know, but should
>>> work for now.
>>>
>>>
>>>
>>>> The important thing is provide something somewhere that can be commonly
>>>> accessed. For example, we could use a map or some generic interface stored
>>>> in externalContext.getApplicationMap(). It that way, we can avoid add
>>>> methods, but we provide what we need just agreeing with the name and what
>>>> does it return. It is not perfect but it is something at least. Is this
>>>> possible alternative feasible?
>>>>
>>>
>>> I personally can't authorise anything, as I'm just a regular EG member
>>> like you are. Only Ed can possibly allow this at this point.
>>>
>>> But I'm afraid it's, unfortunately, simply too late now.
>>>
>>> Kind regards,
>>> Arjan Tijms
>>>
>>>
>>>> regards,
>>>>
>>>> Leonardo Uribe
>>>>
>>>> 2017-02-14 11:41 GMT-05:00 arjan tijms <arjan.tijms_at_gmail.com>:
>>>>
>>>>> Hi Leo,
>>>>>
>>>>> On Tue, Feb 14, 2017 at 12:40 AM, Leonardo Uribe <
>>>>> leonardo.uribe_at_irian.at> wrote:
>>>>>
>>>>>> Hi
>>>>>>
>>>>>> And the two methods proposed in Application class?
>>>>>>
>>>>>> public void addDataModel(Class<?> forClass, String dataModelClass)
>>>>>> public DataModel createDataModel(java.lang.Class<?> forClass, Object
>>>>>> value)
>>>>>>
>>>>>
>>>>> The functionality for addDataModel at least is handled by CDI. That
>>>>> can't be done by such a method, since it has to be done in the CDI
>>>>> extension and the JSF Application class is not necessarily available by
>>>>> then. The other way around, when the Application class is available it's
>>>>> too late for CDI to accept new Bean<T> registrations, let alone annotated
>>>>> types.
>>>>>
>>>>> The createDataModel method is practically there already, it's in
>>>>> Mojarra:
>>>>>
>>>>> private DataModel<?> createDataModel(final Class<?> forClass)
>>>>>
>>>>> I would love to have added this method somewhere publicly, but I'm
>>>>> afraid it's now too late for that :(
>>>>>
>>>>> What you CAN do however, is subclass UIData, then instantiate that.
>>>>> Then do
>>>>>
>>>>> myUIData.setValue(someClassInstance);
>>>>> UIDataModel<?> myModel = myUIData.getDataModel();
>>>>>
>>>>> That should guaranteed give you the right DataModel instance. If it's
>>>>> covered by an existing known type it will return the wrapper for that,
>>>>> otherwise the CDI version will be called.
>>>>>
>>>>> I humbly apologise for my oversight of adding that method at a public
>>>>> place before. This is indeed my mistake. I will update the JavaDoc as you
>>>>> requested to clarify this usage. For the next spec cycle we could add a
>>>>> more convenient mechanism at the earliest opportunity.
>>>>>
>>>>> Once again my apologies and thanks for finding this.
>>>>>
>>>>> Kind regards,
>>>>> Arjan Tijms
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> I think that's the easiest way to fix it, because it standarize the
>>>>>> way to access
>>>>>> registered DataModel classes and encapsulate the algorithm that finds
>>>>>> the right
>>>>>> DataModel from a specified class.
>>>>>>
>>>>>> regards,
>>>>>>
>>>>>> Leonardo Uribe
>>>>>>
>>>>>> 2017-02-13 18:31 GMT-05:00 arjan tijms <arjan.tijms_at_gmail.com>:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> On Mon, Feb 13, 2017 at 11:35 PM, Leonardo Uribe <
>>>>>>> leonardo.uribe_at_irian.at> wrote:
>>>>>>>
>>>>>>>> I have been checking the related documentation of @FacesDataModel
>>>>>>>> and the
>>>>>>>> unofficial explanation in:
>>>>>>>>
>>>>>>>> http://arjan-tijms.omnifaces.org/2015/07/jsf-23-new-feature-
>>>>>>>> registrable.html
>>>>>>>>
>>>>>>>> The feature is ok from a functional perspective, it has sense,
>>>>>>>>
>>>>>>>
>>>>>>> Good! :)
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> It means if UIData.getValue() has a value with type MyCollection,
>>>>>>>> the value
>>>>>>>> will be wrapped in a MyCollectionModel instance. This resembles
>>>>>>>> "targetClass" for Converter instances.
>>>>>>>>
>>>>>>>
>>>>>>> True, that kinda was the inspiration for the particular
>>>>>>> implementation of this feature request.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> But in JSF, there is an Aplication class where you can register
>>>>>>>> Converter
>>>>>>>> instances to apply for an specific "targetClass" and so on. But
>>>>>>>> there is
>>>>>>>> nothing for DataModel.
>>>>>>>>
>>>>>>>
>>>>>>> It basically happens fully via CDI now. Either user provided with
>>>>>>> the @FacesDataModel annotation, or programmatically by adding your own
>>>>>>> annotated classes and/or Bean<T> instances using the CDI API (in an CDI
>>>>>>> extension).
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> no new description in UIData.getDataModel(), nothing.
>>>>>>>>
>>>>>>>
>>>>>>> That's a good point, I'll look at providing something of a
>>>>>>> description there right away.
>>>>>>>
>>>>>>> Thanks again Leo!
>>>>>>>
>>>>>>> Kind regards,
>>>>>>> Arjan Tijms
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>
>