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

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

From: Edward Burns <edward.burns_at_oracle.com>
Date: Mon, 17 Aug 2015 10:43:29 -0700

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

AT> Hi,
AT> 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.

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

It's the same as any scoped CDI bean. For example, @SessionScoped beans.

AT> E.g.

AT> @Named
AT> @RequestScoped
AT> public class Foo {}

AT> ...

AT> somePage.xhtml:

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

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

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

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

AT> ...

AT> somePage.xhtml:

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


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

Not just that. It is three things:

1. the name of the bean
2. the EL reference
3. The fact that the view somePage.xhtml resides within the flow "bar".

If any of those are not met, the bean is not resolved.

For example, let's say the same EL reference is located on a page
outside of any flow:

somePage.xhtml

#{foo.name}

This will not resolve.

Now, let's say we have the same EL in a page in a different flow "foo".

flow foo

somePage.xhtml

#{foo.name}

This will still not resolve because the page is in the foo flow.


AT> With an id you could theoretically do the following:

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

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

AT> ...

AT> bar.xhtml

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

AT> somePage.xhtml:

AT> #{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?

AT> I think just by using @FlowScoped:

AT> @Named
AT> @FlowScoped
AT> public class Foo {}

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

But if you do that, then how can you differentiate multiple beans to be
in different flows.

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

Because the spec says that flow scoped beans must be declared to be in a
specific flow.

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

It seems like you are requesting a new feature: give me a way to have
@FlowScoped beans that are active for any flow. Is that what you're
looking for?

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

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

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

AT> }

Right. Don't conflate the "#{flowScope} implicit object" concept with the
"FlowScoped beans in a flow concept".

If you are in fact looking for a new feature where if the flowId is
missing from the @FlowScoped annotation, the bean is assumed to be in
any flow scope, we can consider that. My instincts say such a feature
would be more trouble than it's worth, though.

>>>>> On Fri, 14 Aug 2015 11:57:51 -0500, Josh Juneau <juneau001_at_gmail.com> said:

JJ> I think that Arjan's explanation sounds solid. Having one less attribute
JJ> to worry about would certainly make things easier for those getting
JJ> started.

I must be missing something. Without the flowId being required how can
the system possibly know that FlowABean is only accessible when the
current flow is FlowA?

flowA/
  page1.xhtml #{flowABean.name} resolves but #{flowBBean.name} does not.

flowB/
  page1.xhtml #{flowABean.name} does not resolve but #{flowBBean.name} resolves.


package my.app

  @FlowScoped("flowA")
  public class FlowABean

  @FlowScoped("flowB")
  public class FlowBBean

If we were to remove the flowId, then both beans would be accessible
from both flows. That's not the intent of the design.

Thanks,

Ed

-- 
| edward.burns_at_oracle.com | office: +1 407 458 0017
| 56 Business days til JavaOne 2015
| 71 Business days til DOAG 2015