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

[jsr372-experts] Re: _at_FlowScoped not entirely consistent?

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Thu, 13 Aug 2015 09:27:30 +0200

Hi,

On Thu, Aug 13, 2015 at 12:34 AM, Edward Burns <edward.burns_at_oracle.com> wrote:
> Spec> FlowScoped is a CDI scope that causes the runtime to consider
> Spec> classes with this annotation to be in the scope of the specified
> Spec> Flow. [...] beans with this annotation are created when
> Spec> the user enters into the specified Flow, and de-allocated when the
> Spec> user exits the specified Flow.
>
> But I don't think it's 100% eager. I think they only get created when
> something such as EL tries to access it.

If they only get created upon access, then isn't it the same as with
every scope that doesn't require an ID?

E.g.

@Named
@RequestScoped
public class Foo {}

...

somePage.xhtml:

#{foo.toString()} <---- gets created at this point

It's not necessary here to use @RequestScoped("somePage").

And now it's seemingly the same with @FlowScoped:

@Named
@FlowScoped("bar")
public class Foo {}

...

somePage.xhtml:

#{foo.toString()} <---- gets created at this point


At this point the id "bar" is not used at all, since it's the name of
the bean "foo" and the EL reference to it that caused the bean to be
created on demand.


With an id you could theoretically do the following:

Suppose a flow with view bar.xhtml and next.xhtml both in the flow.

@Named
@FlowScoped("bar")
public class Foo {}

...

bar.xhtml

(bean "foo" is created when the user enters flow "bar", since the
system can look up the bean by its flow id)

somePage.xhtml:

#{foo.toString()} <---- already exists at this point



> Finally, the main reason the value is necessary is that how else can a
> FlowScoped bean be declared to be in a scope?

I think just by using @FlowScoped:

@Named
@FlowScoped
public class Foo {}

With that the bean "foo" is scoped to whatever the current active flow
is. Technically this is already what happens.

The current implementation code doesn't actually use the flow id on
@FlowScoped, except for a validation that the current flow id matches
with the id (value) of the @FlowScoped annotation. But this is only a
check. If you remove the check and recompile the code everything still
seems to work. Which leads to the question, why is the check there in
the first place?

#{flowScope} is a Map<Object, Object> that's effectively flow scoped
too, but this one does not define a flow id. It simply resolves to the
"current" flow.

Now as a consequence there is a small problem when you want to make a
dynamic producer (Bean<T>) for #{flowScope}. You need to set the scope
of this to @FlowScoped (no value possible here, and even if possible
not wanted):

public class FlowMapProducer extends CdiProducer<Map<Object, Object>> {

    public FlowMapProducer() {
        super.name("flowScope")
             .scope(FlowScoped.class) // <------- problematic with
current implementation
             .qualifiers(new FlowMapAnnotationLiteral())
             .types(
                 new ParameterizedTypeImpl(Map.class, new
Type[]{Object.class, Object.class}),
                 Map.class,
                 Object.class)
             .beanClass(Map.class)
             .create(e ->
FacesContext.getCurrentInstance().getApplication().getFlowHandler().getCurrentFlowScope());
    }

}

In this case the Map needs to be retrieved from the *current* flow
scope, and so for this definition it makes no sense to put a value
that represents a specific flow id somewhere.

This case too works when I remove the check for the matching flow IDs.
(there's an alternative solution as well, but that too boils down to
simply not doing the check).

Kind regards,
Arjan Tijms






>
> Ed
>
> --
> | edward.burns_at_oracle.com | office: +1 407 458 0017
> | 59 Business days til JavaOne 2015
> | 74 Business days til DOAG 2015