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

[jsr372-experts] Re: [jsr372-experts mirror] Re: remove final from methods in UIComponent to make them proxyable in CDI

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Fri, 16 Dec 2016 17:40:56 -0500

Hi

I did some tests in order to verify how far can we go with this idea.

The conclusion is CDI API does not provide a way to create a Producer
flexible enough to fit JSF needs, but at least OpenWebbeans provide an
implementation specific way to create the proxy we need to fix
"binding" attribute. That means we can't include it as an standard
feature in JSF 2.3, but if final modifiers are removed from UIComponent
we can do an implementation specific fix using OWB (and in that way
include it partially in 2.3).

I'm going to do a detailed explanation, even if this is repetitive,
because maybe this is something we could ask to CDI EG guys to be
included in a future release of CDI, or maybe we can just do the
required change, remove final modifiers now and open this possibility.

What users want is to make this case possible in JSF:

@Named
@ViewScoped
public class CustomBean implements Serializable
{

    private HtmlInputText name; //Injected through "binding" attribute.

    // ...
}

There is no doubt UIComponent instances are managed by JSF, because the
component tree is generated by JSF. That means JSF should be responsible
of create the component and set it into the CDI Bean. The problem right
now is the component instance is set "as is" so when the view scope bean
is serialized, the UIComponent instance is serialized into the state too,
so it creates a duplicate instance that cause some other problems.

The solution from a theoretical perspective is create a proxy class that
can be serialized/deserialized, but with the ability of delegate to the
real instance in the component tree.

CDI provide Producer Methods, but these methods does not handle generics,
so the only option is create one producer method per component class in
JSF. JSF contains a list of component classes in Application object, but
the list is required when CDI is initialized, which is way before JSF
initialization. It is possible to split JSF init in two and move it as a
CDI extension, but that's overkill, too difficult to do (JSF still need
to read web.xml to build FacesConfig tree).

But in OWB there is a way to get the proxy we need in this way
(bypassing somehow CDI):

UIComponent component =
        WebBeansContext.currentInstance().getNormalScopeProxyFactory()
                .createNormalScopeProxy(new CustomComponentProducer());

CustomComponentProducer is a class implementing Bean<T>. Internally there
is a 1:1 relation between the bean or producer instance and the proxy,
so in JSF it should be cached 1 bean per UIComponent class to avoid
OutOfMemoryExceptions.

The missing piece of the puzzle is CDI does not have a way to register
a producer method on runtime. If we had that, we could register the
producer in a lazy way from Application object and then use the
producer when "binding" attribute is set.

Does the proposal of remove "final" modifiers from UIComponent methods
makes sense? Yes. The problem is make a change in CDI could take 1
release and only after that we could include it officially in JSF, so
it could take years to include something we can do now, even with
some limitations. Do not remove the "final" modifiers means block this
issue to be solved almost forever.

Is it a big deal? well, now you need 2 managed beans, one view scope bean
and other request scope bean with the UIComponent instances per use case
in a page. The fix reduce the beans used by half and that means a lot
more simplicity when writing code.

regards,

Leonardo Uribe

2016-12-15 19:08 GMT-05:00 Leonardo Uribe <leonardo.uribe_at_irian.at>:

> Hi
>
> The table in :
>
> http://arjan-tijms.omnifaces.org/p/jsf-23.html#1316
>
> The one used in the presentation for JSF 2.3. See the line that says:
>
> View #{view} - javax.faces.component.UIViewRoot
>
> It should be somewhere in the spec, but I do not have the PDF or know
> where is in the javadoc.
>
> regards,
>
> Leonardo Uribe
>
>
>
> 2016-12-15 18:44 GMT-05:00 Edward Burns <edward.burns_at_oracle.com>:
>
>> >>>>> On Thu, 15 Dec 2016 17:10:37 -0500, Leonardo Uribe <
>> leonardo.uribe_at_irian.at> said:
>>
>> LU> 1. Change the table to exclude UIViewRoot from injection.
>> LU> 2. Do the change removing "final" modifiers and include UIViewRoot as
>> CDI
>> LU> injectable, do not inject components for current version.
>> LU> 3. Do the change and make components injectable.
>>
>> 2016-12-15 17:23 GMT-05:00 manfred riem <manfred.riem_at_oracle.com>:
>>
>> MR> As previously stated we already did explore this early on in the 2.3
>> MR> cycle and have concluded it is too complex for its perceived
>> MR> benefits.
>>
>> >>>>> On Thu, 15 Dec 2016 17:44:39 -0500, Leonardo Uribe <
>> leonardo.uribe_at_irian.at> said:
>>
>> LU> I don't know. Sometimes different persons trying to solve the same
>> LU> problem can find different solutions.
>>
>> LU> The good news is we can make 2 or 3 at any time, even if it is not
>> LU> now. But as I said, I do not want to throw the towel for include
>> LU> this in JSF 2.3, not until I do one last push.
>>
>> Thanks for making one last push, but this is too scary to re-open. I
>> recall how messy it quickly got when I tried to do it.
>>
>> Manfred for my convenience, please let me know what table to modify for
>> Option 1.
>>
>> Thanks,
>>
>> Ed
>>
>> --
>> | edward.burns_at_oracle.com | office: +1 407 458 0017
>> | 36 business days until DevNexus 2017
>> | 61 business days until JavaLand 2017
>>
>
>