Injecting a Provider<GoodbyePlace> into your certainly works. We opted
to repurpose the AppPlaceFactory for this, however. In addition to the
required methods returning the tokenizer, we have convenience methods
to get a new place:

  GoodbyePlace.Tokenizer getGoodbyeTokenzer() { ... }

  GoodbyePlace goodbyePlace(/*any required params here*/) {
    return goodbyePlaceProvider.get().init( /* required params */) ;
  }

Since GoodbyePlace is being constructed by Gin, we wouldn't otherwise
have an opportunity to pass in required parameters (e.g.
EditPersonPlace requires a personId) to the constructor. Since certain
places have required parameters (e.g. EditPersonPlace requires
personId), y convention, we're going with an init() method that
accepts the required arguments. Other arguments can be later set with
a setter. This isn't ideal, as our Place aren't immutable anymore,
which I think they should be, but I don't see an alternative.

- Amir

On Oct 22, 7:34 am, David Chandler <[email protected]> wrote:
> Thanks for sharing your code also, Aodhagán. As both you and Amir have
> pointed out, there is not necessarily a 1:1 correspondence between
> Activity and Place, so the notion of an ActivityPlace may not fit
> every situation.
>
> > Where I do have an issue now though is actually going to a new Place?
>
> > From HelloMVP - HelloView:
> > listener.goTo(new GoodbyePlace(name));
>
> You would need to inject Provider<GoodbyePlace> into HelloViewImpl in
> order to obtain a GoodbyePlace on which you would then call setName().
>
> Perhaps this better belongs in the HelloActivity instead, in which
> case you might use a method like listener.sayGoodbye(String name),
> which in turn calls the injected Provider<GoodbyePlace>.
>
> HTH,
>
>
>
>
>
>
>
> On Fri, Oct 22, 2010 at 5:48 AM, Aigeec <[email protected]> wrote:
> > Hey Amir,
>
> > That is pretty much where I got to. I don't use a clientfactory and
> > have replaced it with GIN injection. I don't use a Factory to create
> > the Activity as I have implemented my ActivityPlace slightly
> > differently.
>
> > Let me know if I have gone completely crazy or have missed some
> > fundamental point of the Activities/Places :
>
> > public abstract class ActivityPlace<T extends Activity> extends Place
> > {
>
> >        private T activity;
>
> >        public ActivityPlace(T activity) {
> >                this.activity = activity;
> >        }
>
> >        public T getActivity(){
> >                return activity;
> >        }
>
> > }
>
> > My Place class then looks like this:
>
> > public class AboutPlace extends ActivityPlace<AboutActivity> {
>
> > private String name;
>
> >       �...@inject
> >        public AboutPlace(AboutActivity activity)
> >        {
> >                super(activity);
> >        }
>
> >        public void setName(String token){
> >                this.name = token;
> >        }
>
> >        public String getName()
> >        {
> >                return name;
> >        }
>
> >        public static class Tokenizer implements PlaceTokenizer<AboutPlace>
> >        {
> >                private final Provider<AboutPlace> placeProvider;
>
> >               �...@inject
> >                public Tokenizer(Provider<AboutPlace> placeProvider){
> >                        this.placeProvider = placeProvider;
> >                }
>
> >                public AboutPlace getPlace(String token) {
>
> >                        AboutPlace place = placeProvider.get();
>
> >                        place.setName(token);
>
> >                        return place;
>
> >                }
>
> >                public String getToken(AboutPlace place) {
>
> >                        return place.getName();
>
> >                }
>
> >        }
>
> > }
>
> > The bit I had been missing was the PlaceProvider within the Tokenizer
> > but thanks to your post was able to resolve this.
>
> > Again I am are binding a place to an activity which as you have stated
> > could be an issue with regard to scalability.
> > However was this not the case using the "sounding less onerous" if
> > statements and where activities were bound to places.
>
> > I may have missed something be how do you facilitate the passing of a
> > token to the place?
>
> > Where I do have an issue now though is actually going to a new Place?
>
> > From HelloMVP - HelloView:
> > listener.goTo(new GoodbyePlace(name));
>
> > Regards,
>
> > Aodhagán
>
> > On Oct 21, 9:34 pm, Amir Kashani <[email protected]> wrote:
> >> I work with Tolga, who started the thread on GWTC. Here's the solution
> >> we came up with based on David's initial suggestion there.
>
> >> 1) We created a base class called ActivityPlace, that has an abstract
> >> getActivty() method:
> >>    public Activity getActivity();
>
> >> 2) Thus, the the getActivity method in ActivityMapper is reduced to
> >> the following:
>
> >>     @Override
> >>     public Activity getActivity(Place place) {
>
> >>         if (place instanceof ActivityPlace) {
> >>             return ((ActivityPlace) place).getActivity();
> >>         }
>
> >>         return null;
> >>     }
>
> >> 3) A typical Place then looks like this:
>
> >>     public class TestPlace extends ActivityPlace {
>
> >>         public static class Tokenizer implements
> >> PlaceTokenizer<TestPlace> {
>
> >>             // Since the place is injectable, we'll let Gin do the
> >> construction.
> >>             private final Provider<TestPlace> placeProvider;
>
> >>             @Inject
> >>             public Tokenizer(Provider<TestPlace> placeProvider) {
> >>                 this.placeProvider = placeProvider;
> >>             }
>
> >>             @Override
> >>             public String getToken(TestPlace place) {
> >>                 return null;
> >>             }
>
> >>             @Override
> >>             public TestPlace getPlace(String token) {
> >>                 return placeProvider.get();
>
> >>                 // If place requires any more work, do it here.
> >>             }
> >>         }
>
> >>         private Provider<TestActivity> activityProvider;
>
> >>         @Inject
> >>         public TestPlace(Provider<TestActivity> activityProvider) {
> >>             this.activityProvider = activityProvider;
> >>         }
>
> >>         @Override
> >>         public Activity getActivity() {
> >>             // Can't inject Place into the constructor, so by
> >> convention, we're using init(Place p) in our Activites to pass the
> >> place in.
>
> >>             return activityProvider.get().init(this);
> >>         }
>
> >>     }
>
> >> 4) Then, we create our PlaceHistoryMapperWithFactory:
> >>     public interface AppPlaceHistoryMapper extends
> >> PlaceHistoryMapperWithFactory<AppPlaceFactory> { // empty }
>
> >>    Notice there are no Tokenizer annotations here -- they're no longer
> >> needed.
>
> >> 5) And the actual factory looks like this:
>
> >>   public class AppPlaceFactory {
>
> >>     // A single instance of the tokenizer should work, since they
> >> don't have state.
> >>     @Inject
> >>     TestPlace.Tokenizer testPlaceTokenizer;
>
> >>     @Inject
> >>     Provider<TestPlace> test;
>
> >>     public TestPlace.Tokenizer getTestPlaceTokenizer() {
> >>         return testPlaceTokenizer;
> >>     }
>
> >>     // Not required by the factory, but since TestPlace is GIN
> >> injectable, the constructor might be too complex to construct by hand.
> >>     public TestPlace getTest() {
> >>         return test.get();
> >>     }
> >>   }
>
> >>   I think others may have made their Ginjector the factory -- we opted
> >> to keep it separate, but it doesn't make much difference.
>
> >> So, after all that, the process for creating a new Place is simply
> >> create the Place and associated Tokenizer, and add a method inside the
> >> factory to retrieve the Tokenizer (the generator looks for any no-arg
> >> methods that return a Tokenizer).
>
> >> What gets more complicated and may prove this approach unscalable is
> >> that the Place is tied directly to the Activity. There may be some
> >> scenarios, where PlaceA has a different Activity, depending on the
> >> ActivityManager and the display region. An ActivityMapper could choose
> >> to ignore the Place.getActivty() method, but it might be awkward.
>
> >> We'd love some feedback on this and to see what other people are
> >> doing.
>
> >> - Amir
>
> >> On Oct 21, 12:15 pm, David Chandler <[email protected]> wrote:
>
> >> > Hi Yuan,
>
> >> > Unfortunately, the mere mention of a need for something does not imply
> >> > its current availability :-) I wrote the Activities and Places doc and
> >> > really should have left GIN out of it for the time being. The root
> >> > issue is that GIN does not have a way to createMeA(Foo.class), as such
> >> > a method might impede the GWT compiler's ability to do whole program
> >> > optimization as it does today.
>
> >> > Thus, the only way to implement ActivityMapper.getActivity() or
> >> > PlaceHistoryMapper.getPlace() using GIN would be to return an instance
> >> > of an Activity or Place that has previously been instantiated by GIN
> >> > and injected into to the mapper class. In other words, each Activity
> >> > and Place would have to be a singleton, much like Presenter and Place
> >> > are in the gwt-presenter framework. But in GWT 2.1, Activity and Place
> >> > are designed to be disposable, not singletons, which leaves us with
> >> > the need for "if (place instanceof SomePlace) return new
> >> > SomePlace()..." It seems like it would be possible to create
> >> > SomeActivityFactory and SomePlaceFactory classes bound as singletons
> >> > in GIN gwt-presenter style, which in turn provide newly-created
> >> > instances of SomeActivity and SomePlace, but that requires lots of
> >> > boilerplate code...
>
> >> > As for the onerous chain of if statements (which is sounding less
> >> > onerous all the while), it could be created at compile time using a
> >> > GWT generator, just as GWT's PlaceHistoryMapperGenerator generates a
> >> > sub-class of AbstractPlaceHistoryMapper using @WithTokenizers from
> >> > your PlaceHistoryMapper interface. The advantage of creating your own
> >> > PlaceHistoryMapper base class and generator would be the ability to
> >> > pass a ClientFactory or factory-managed objects to newly constructed
> >> > Places. That is, the generated code could do
>
> >> > if (token.startsWith("SomePlace"))
> >> >     return new SomePlace(clientFactory, token);
> >> > else if (token.startsWith("AnotherPlace"))
> >> >     return new AnotherPlace(clientFactory, token);
> >> > ...
>
> >> > Hope that helps someone...
>
> >> > The GWT team is working hard to make this easier in a future point 
> >> > release.
>
> >> > /dmc
>
> >> > On Thu, Oct 21, 2010 at 3:09 AM, Yuan <[email protected]> wrote:
> >> > > can't use gin at ActivityMapper? somehower, on the HelloMVP
> >> > > AppActivityMapper,
> >> > > it says...
>
> read more »

-- 
You received this message because you are subscribed to the Google Groups 
"Google Web Toolkit" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.

Reply via email to