Thanks, I hadn't thought of that.

The way we're minimizing code right now, is by creating some useful
abstract tokenizers that handle the common use cases (no parameter
tokenizer, key-value pair tokenizer). With those there are
corresponding abstract tokenizers that handle creating the hashCode
and equals methods.

Aside from the 1:1 between Place and Activity, which bothers me in
principle but may not be a practical concern just yet, it's coming
along pretty nicely.

- Amir

On Oct 22, 7:11 am, David Chandler <drfibona...@google.com> wrote:
> Thanks for sharing your code, Amir. It's great to see this fleshed
> out. One possible simplification is to eliminate PlaceTokenizers
> entirely. These are required by the generated PlaceHistoryMapper, but
> you are free to create your own implementation of PlaceHistoryMapper
> which does not use Tokenizers. This would be inferior from a
> dependency injection of view as it still results in a chain of if
> statements, but eliminates a lot of code. Here's an example which
> doesn't use GIN:
>
> public class SimplePlaceMapper implements PlaceHistoryMapper {
>         private ClientFactory clientFactory;
>
>         public SimplePlaceMapper(ClientFactory cf) {
>                 this.clientFactory = cf;
>         }
>
>         @Override
>         public Place getPlace(String token) {
>                 if (token.startsWith("helloPlace"))
>                         return new HelloPlace(clientFactory, token);
>                 else if (token.startsWith("goodbyePlace"))
>                         return new GoodbyePlace(clientFactory, token);
>                 return null;
>         }
>
>         @Override
>         public String getToken(Place place) {
>                 if (place instanceof ActivityPlace)
>                         return ((ActivityPlace) place).getToken();
>                 return null;
>         }
>
> }
>
> Note that ActivityPlace has one additional method, getToken():
>
> public abstract class ActivityPlace<T extends Activity> extends Place {
>         public abstract T getActivity();
>         public abstract String getToken();
>
> }
>
> You need this in your gwt.xml to turn off the
> PlaceHistoryMapperGenerator that will otherwise try to generate a
> class replacing SimplePlaceHistoryMapper:
>
>    <replace-with
> class="com.google.gwt.sample.hellomvp.client.mvp.SimplePlaceMapper">
>        <when-type-assignable
> class="com.google.gwt.place.shared.PlaceHistoryMapper" />
>    </replace-with>
>
> You could make a GIN-aware PlaceHistoryMapper, as well, which could
> call Provider.get() as you're doing; however, this would require some
> gwt.xml hackery because a rebind rule like the above doesn't work with
> GIN. At least, I haven't gotten it to work yet...
>
> /dmc
>
>
>
>
>
>
>
> On Thu, Oct 21, 2010 at 4:34 PM, Amir Kashani <amirkash...@gmail.com> 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 <drfibona...@google.com> 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 <yuan.w0...@gmail.com> wrote:
> >> > can't use gin at ActivityMapper? somehower, on the HelloMVP
> >> > AppActivityMapper,
> >> > it says
>
> >> >        public Activity getActivity(Place place) {
> >> >                // This is begging for GIN
> >> >                if (place instanceof HelloPlace)
> >> >                        return new HelloActivity((HelloPlace) place, 
> >> > clientFactory);
> >> >                else if (place instanceof GoodbyePlace)
> >> >                        return new GoodbyeActivity((GoodbyePlace) place, 
> >> > clientFactory);
>
> >> >                return null;
> >> >        }
>
> >> > On Oct 20, 3:22 pm, Thomas Broyer <t.bro...@gmail.com> wrote:
> >> >> On 20 oct, 11:42, Sebastian Beigel <sebast...@beigel.de> wrote:
>
> >> >> > Hi,
>
> >> >> > I'm looking at 2.1 (RC1) for the first time right now and I try to
> >> >> > refactor the hellomvp sample to use GIN.
>
> >> >> > Unfortunately, I have some problems with the places -> activities
> >> >> > mapping. The doc says "A better way to implement the chain of nested
> >> >> > ifs would be with a GIN module." and the code is commented "Map each
> >> >> > Place to its corresponding Activity. This would be a great use for
> >> >> > GIN.".
>
> >> >> > I agree, but I don't really know how to do this mapping :) Has anyone
> >> >> > refactored this code to use GIN?
>
> >> >> You just can't actually. What could work is using a Ginjector as the
> >> >> factory of a PlaceHistoryMapperWithFactory, but for ActivityMapper
> >> >> this is not possible (it could be by adding a code generator using a
> >> >> factory of activity factories, similar to the factory of place
> >> >> tokenizers (which are kind of factories for places) for
> >> >> PlaceHistoryMapperWithFactory).
> >> >> I wrote an code generator for ActivityMapper some time ago <http://gwt-
> >> >> code-reviews.appspot.com/845802/show> it won't do what you're asking
> >> >> for but could probably be...
>
> 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 google-web-tool...@googlegroups.com.
To unsubscribe from this group, send email to 
google-web-toolkit+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.

Reply via email to