GWT 2.1 hellomvp using GIN

1,608 views
Skip to first unread message

Sebastian Beigel

unread,
Oct 20, 2010, 5:42:23 AM10/20/10
to Google Web Toolkit
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?

Thank you,
Sebastian

Marcin Misiewicz

unread,
Oct 20, 2010, 6:29:40 AM10/20/10
to Google Web Toolkit
Well I'm also very interested in some guidelines of how to use gin
with activities and places.

Fernando Barbat

unread,
Oct 20, 2010, 6:31:45 AM10/20/10
to Google Web Toolkit
I had the exactly same doubt. And I thought about it, but couldn't
find out how you can do that mapping with GIN.
In fact, Roo's generated projects don't use a GIN-based mapping
although they use GIN in other parts.

So I'm interested to know the answer to this question too. :P

moejo

unread,
Oct 20, 2010, 5:05:40 PM10/20/10
to Google Web Toolkit
I don't know if this will help, but i recreated the Contact Details
app which is under the "Large scale application development" article
at http://code.google.com/webtoolkit/articles/mvp-architecture.html
using just a clientFactory to allow a more thorough working example
using GWT 2.1 Activities and Places to play with. You can find it
under my blog at:

http://www.bright-creations.com/blog/gwt-2-1-mvp-client-factory-example/

It's still not using GIN, but my task for tonight (and it's already 11
p.m. so better get my backside moving) is that I'm in the process of
seeing how to inject references using GIN. Í'll let you know the
outcome.

In the meantime, if this helps anyone with playing with GIN and
activities, and you manage to get it done quicker than I can, then let
me know and I'd love to link to it. Otherwise, i'll let you know the
outcomes asap.

Moe

Thomas Broyer

unread,
Oct 20, 2010, 5:22:55 PM10/20/10
to Google Web Toolkit
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 used as a basis for it. But you'd first have
to decide how to model a "factory of activities" that would be
returned by your "Ginjector as a factory for
ActivityMapperWithFactory".

Sebastian Beigel

unread,
Oct 21, 2010, 5:59:02 AM10/21/10
to google-we...@googlegroups.com
Thank you Thomas,

that's what I was thinking -- and I'm playing with a custom code
generator already :)

Just wondering what "they" mean with the GIN comments in the doc/code...

In my pre-2.1 homegrown framework I use a code-generated presenter
config based on a Ginjector (declaring all the getFooPresenter()
methods annotated with location (place) and security informations). My
presenters were singletons and were "started" with the actual Place.
That way I could use GIN to (constructor) inject all my dependencies.
I'm not sure if I like this 2.1-design (constructing activities with
the actual place) which means I cannot use GIN to construct them.
Maybe I make my activities extends some AbstractBaseActivity
containing a setPlace(P place) method which is called in the
ActivityMapper...

Sebastian

> --
> 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-we...@googlegroups.com.
> To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
>
>

Richard Allen

unread,
Oct 21, 2010, 8:12:27 AM10/21/10
to Google Web Toolkit
There is another thread on the GWT contributors group about this
topic.
http://groups.google.com/group/google-web-toolkit-contributors/browse_thread/thread/732e66a858a8ef0b/38a3f36ffc1767a0

-Richard

Yuan

unread,
Oct 21, 2010, 3:09:52 AM10/21/10
to Google Web Toolkit
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;

David Chandler

unread,
Oct 21, 2010, 3:15:32 PM10/21/10
to google-we...@googlegroups.com
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

> --
> 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-we...@googlegroups.com.
> To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
>
>

--
David Chandler
Developer Programs Engineer, Google Web Toolkit
http://googlewebtoolkit.blogspot.com/

Amir Kashani

unread,
Oct 21, 2010, 4:34:24 PM10/21/10
to Google Web Toolkit
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
> > For more options, visit this group athttp://groups.google.com/group/google-web-toolkit?hl=en.

Rodrigue Lagoue Njinthe

unread,
Oct 21, 2010, 4:46:30 PM10/21/10
to google-we...@googlegroups.com
Hi all,

I would like to know if it's possible to customize the style of CellTable's
header. For example headers looking like buttons.

Thanks for any help

Rodrigue

Thomas Broyer

unread,
Oct 22, 2010, 6:27:11 AM10/22/10
to Google Web Toolkit

On 21 oct, 21:15, 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()..."

There are Provider<?>s for that use case:
@Inject Provider<Foo> fooProvider;
...
Foo foo = fooProvider.get(); // returns a new instance, unless the
toProvider() has been bound in(Singleton.class).


> 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...

That's what AssistedInject (coming in GIN 1.1, which is waiting for a
Guice 2.1 release) aims at solving.
http://code.google.com/p/google-guice/wiki/AssistedInject

What I think might be missing to GIN is the ability to have assisted
injection within the Ginjector:
interface ClientFactory extends Ginjector {
FooActivity fooActivity(FooPlace fooPlace);
}

But it might be possible to work around this with a GWT code
generator:
1. make an "assisted inject" "base" factory interface:
public interface ActivityFactory<A extends Activity, P extends Place>
{
A create(P place);
}
2. create an ActivityMapperWithFactory<?> interface extending
ActivityMapper
3. have a code generator look at the factory, providing
ActivityFactory<?,?> instances through no-arg methods, in the same way
PlaceHistoryMapperWithFactory is generated today and can already be
used with a Ginjector as a factory for PlaceTokenizer<?>s

From the user (developer) POV:
1. extend ActivityFactory:
public interface FooActivityFactory extends ActivityFactory<Foo,
FooPlace> { }
2. create a Ginjector as a factory of ActivityFactory instances:
@GinModules(MyGinModule.class)
public interface MyGinjector extends Ginjector {
FooActivityFactory fooActivityFactory();
BarActivityFactory barActivityFactory();
}
3. extend ActivityMapperWithFactory:
public interface MyActivityMapper extends
ActivityMapperWithFactory<MyGinjector> { }

The code generator invoked by GWT.create(MyActivityMapper.class) (i.e.
by simply injecting a MyActivityMapper without any specific binding)
would then generate:
if (place instanceof Foo) return
factory.fooActivityFactory().create((Foo) place);
if (place instanceof Bar) return
factory.barActivityFactory().create((bar) place));

Steps 1 and 2 could be avoided if GIN allowed assisted injection right
at the Ginjector level (see above); which I believe is not currently
possible (I'd love to be proved wrong on that)


Aigeec

unread,
Oct 22, 2010, 5:48:11 AM10/22/10
to Google Web Toolkit
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

David Chandler

unread,
Oct 22, 2010, 10:11:37 AM10/22/10
to google-we...@googlegroups.com
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

> For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

David Chandler

unread,
Oct 22, 2010, 10:34:03 AM10/22/10
to google-we...@googlegroups.com
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,

> For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Richard Allen

unread,
Oct 22, 2010, 11:24:02 AM10/22/10
to Google Web Toolkit
How would you all envision code splitting working with these examples?
For example, if you want to code split an activity and view, and then
restrict access to that code with a permission check.

I would like to be able to split out code that the user does not have
permission to use so they don't even get that code loaded in the
browser. If the user tries to navigate to a place for which they do
not have permission, then the application can either treat that place
as unknown or have only enough knowledge (code) of the place to let
the user know they don't have permission to access it.

I have just recently starting prototyping using the GWT 2.1 MVP
framework, and I don't yet see a path for a solution to this problem
with the current design of the mappers. Of course, I may simply be
missing the key.

-Richard
> >> > > it says...
>
> read more »

Amir Kashani

unread,
Oct 22, 2010, 1:23:11 PM10/22/10
to Google Web Toolkit
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
> >> > > it says...
>
> read more »

Amir Kashani

unread,
Oct 22, 2010, 1:31:59 PM10/22/10
to Google Web Toolkit
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
> >> >> for but could probably be...
>
> read more »

David Chandler

unread,
Oct 22, 2010, 1:50:58 PM10/22/10
to google-we...@googlegroups.com
Hi Richard,

We're still working on an official story for how best to use runAsync
with Activities and Places. In the mean time, feedback on your
experiences is welcome. GWT's AsyncProxy class or the AsyncProvider in
GIN trunk look promising as ways to wrap Activity creation with a
runAsync() call.

If view creation is initiated only through the corresponding Activity,
then wrapping Activity creation with runAsync() will defer loading of
the view code also, and you'll be able to see this in the SOYC report.

References:
http://code.google.com/webtoolkit/doc/latest/DevGuideCodeSplitting.html
http://code.google.com/webtoolkit/doc/latest/DevGuideCompileReport.html

HTH,

Thomas Broyer

unread,
Oct 22, 2010, 5:58:48 PM10/22/10
to Google Web Toolkit


On 22 oct, 19:50, David Chandler <drfibona...@google.com> wrote:
> Hi Richard,
>
> We're still working on an official story for how best to use runAsync
> with Activities and Places. In the mean time, feedback on your
> experiences is welcome. GWT's AsyncProxy class or the AsyncProvider in
> GIN trunk look promising as ways to wrap Activity creation with a
> runAsync() call.
>
> If view creation is initiated only through the corresponding Activity,
> then wrapping Activity creation with runAsync() will defer loading of
> the view code also, and you'll be able to see this in the SOYC report.
>
> References:
> http://code.google.com/webtoolkit/doc/latest/DevGuideCodeSplitting.html
> http://code.google.com/webtoolkit/doc/latest/DevGuideCompileReport.html

Just so it doesn't get forgotten, see also
http://code.google.com/p/google-web-toolkit/issues/detail?id=5129
I implemented the proposed ActivityAsyncProxy (see comment #4, as a
concrete class, passing a GIN Provider<Activity> to the constructor)
as a proof-of-concept but haven't used it yet (to tell the truth, not
even tested it), so I cannot comment on how well/bad it works.

moejo

unread,
Oct 23, 2010, 5:54:41 PM10/23/10
to Google Web Toolkit
Hi All,

I'm working on getting an example together and I am having issues
setting up the injectors for the code you've suggested above (Amir,
david, Aodhagán). So far, I've setup everything as you've suggested
for the AppActivityMapper, AppPlaceFactory, AppPlaceHistoryMapper,
Places and ActivityPlace. However, I am obviously missing something
in the GIN module itself (apologize in advance, just started to use
GIN).

The pages are changing successfully, but no history token changes are
made.

The error i get is:

Caused by: com.google.gwt.event.shared.UmbrellaException: One or more
exceptions caught, see full set in UmbrellaException#getCauses
at
com.google.gwt.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:
214)

Caused by: java.lang.NullPointerException: null
at
com.google.gwt.sample.contacts.client.mvp.AppPlaceHistoryMapperImpl.getPrefixAndToken(AppPlaceHistoryMapperImpl.java:
24)
at
com.google.gwt.place.impl.AbstractPlaceHistoryMapper.getToken(AbstractPlaceHistoryMapper.java:
66)
at
com.google.gwt.place.shared.PlaceHistoryHandler.tokenForPlace(PlaceHistoryHandler.java:
156)
at com.google.gwt.place.shared.PlaceHistoryHandler.access
$1(PlaceHistoryHandler.java:151)
at com.google.gwt.place.shared.PlaceHistoryHandler
$1.onPlaceChange(PlaceHistoryHandler.java:103)
at
com.google.gwt.place.shared.PlaceChangeEvent.dispatch(PlaceChangeEvent.java:
57)
at
com.google.gwt.place.shared.PlaceChangeEvent.dispatch(PlaceChangeEvent.java:
1)
at
com.google.gwt.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:
204)
at
com.google.gwt.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:
103)
at
com.google.gwt.place.shared.PlaceController.goTo(PlaceController.java:
120)
at com.google.gwt.sample.contacts.client.activity.ContactActivity
$1.onClick(ContactActivity.java:94)

My NewContactPlace is as follows:

public class NewContactPlace extends
ActivityPlace<EditContactActivity> {

@Inject
public NewContactPlace(EditContactActivity activity) {
super(activity);
GWT.log("NewContactPlace.ActivityProvider: " + activity);
}

private String placeName;

public void setPlaceName(String token) {
this.placeName = token;
}

public String getPlaceName() {
return placeName;
}

@Prefix("new")
public static class Tokenizer implements
PlaceTokenizer<NewContactPlace> {

// Since the place is injectable, we'll let Gin do the construction.
private final Provider<NewContactPlace> placeProvider;

@Inject
public Tokenizer(Provider<NewContactPlace> placeProvider) {
this.placeProvider = placeProvider;
GWT.log("NewContactPlace.Tokenizer.PlaceProvider: " +
placeProvider);
}

@Override
public String getToken(NewContactPlace place) {
return place.getPlaceName();
}

@Override
public NewContactPlace getPlace(String token) {
NewContactPlace place = placeProvider.get();
place.setPlaceName(token);
return place;
// If place requires any more work, do it here.
}

}
}

However, (and I'm pretty sure here's the problem, is my GINModule:

@Override
protected void configure() {

// bind the EventBus
bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);

bind(PlaceController.class).to(InjectablePlaceController.class).in(Singleton.class);

// bind the mapper

bind(ActivityMapper.class).to(AppActivityMapper.class).in(Singleton.class);

// bind the views
bind(IContactsViewDisplay.class).to(ContactsView.class);
bind(IEditDisplay.class).to(EditContactView.class);

}

I've not used providers before, so I'm guessing I need to define a
provider? or is there somewhere else I might be missing.

Any help would be much appreciated.

Cheers

Moe

On Oct 22, 11:58 pm, Thomas Broyer <t.bro...@gmail.com> wrote:
> On 22 oct, 19:50, David Chandler <drfibona...@google.com> wrote:
>
> > Hi Richard,
>
> > We're still working on an official story for how best to use runAsync
> > with Activities and Places. In the mean time, feedback on your
> > experiences is welcome. GWT's AsyncProxy class or the AsyncProvider in
> > GIN trunk look promising as ways to wrap Activity creation with a
> > runAsync() call.
>
> > If view creation is initiated only through the corresponding Activity,
> > then wrapping Activity creation with runAsync() will defer loading of
> > the view code also, and you'll be able to see this in the SOYC report.
>
> > References:
> >http://code.google.com/webtoolkit/doc/latest/DevGuideCodeSplitting.html
> >http://code.google.com/webtoolkit/doc/latest/DevGuideCompileReport.html
>
> Just so it doesn't get forgotten, see alsohttp://code.google.com/p/google-web-toolkit/issues/detail?id=5129

moejo

unread,
Oct 23, 2010, 6:03:45 PM10/23/10
to Google Web Toolkit
Sorry, feel like I might be missing some info to you. I've basically
got two items:

3 Places
- ContactPlace
- EditContactPlace
- NewContactPlace

which map to 2 activities:
- ContactActivity
- EditContactActivity

the contact activity is initally loading fine, but there is a click to
add a new contact which is supposed to load the NewContactPlace.

I'm passing the provider to the ContactActivity as so:

@Inject
public ContactActivity(EventBus eventBus, IContactsViewDisplay
display,
PlaceController placeController,
ContactsServiceAsync rpcService,
Provider<NewContactPlace> newGoToPlaceProvider,
Provider<EditContactPlace> editGoToPlaceProvider) {
this.rpcService = rpcService;
this.eventBus = eventBus;
this.display = display;
this.placeController = placeController;

this.newGoToPlaceProvider = newGoToPlaceProvider;
this.editGoToPlaceProvider = editGoToPlaceProvider;
}

And forwarding to the newcontactplace here:

ContactActivity.this.placeController.goTo(newGoToPlaceProvider.get());

It's the above line (that although it kicks off and moves to the New
Contact Page, it's giving a null pointer exception and not updating
the URL.

My AppPlaceFactory is exactly as Amir mentioned above.

Would really appreciate some help on this.

Cheers

Moe

Henrik Schmidt

unread,
Oct 23, 2010, 8:24:14 PM10/23/10
to Google Web Toolkit
I've been playing around with this for som time. I can't see a more
reasonable solution than the one Amir and Aigeec proposed.

Sure, the getActivity method with a long list of if-the-else's doesn't
seem nice, but this alternative is just too much boilerplate for my
liking. Lots of Provider classes with the only benefit of avoiding one
ugly method seems to be more trouble than it's worth.

In other words, I gonna stick with the below until something better
comes along:

public class AppActivityMapper implements ActivityMapper {

private AppGinjector injector;

@Inject
public AppActivityMapper(MailGinjector injector) {
this.injector = injector;
}

@Override
public Activity getActivity(Place place) {
if (place instanceof HelloPlace) {
return injector.getHelloActivity().withPlace((HelloPlace)
place);
}
else if (place instanceof GoodbyePlace) {
return
injector.getGoodbyeActivity().withPlace((GoodbyePlace) place);
}
return null;
}
}

Henrik Schmidt

unread,
Oct 23, 2010, 8:27:11 PM10/23/10
to Google Web Toolkit
Oops. Substitute MailGinjector with AppGinjector. I'm playing around
with the Mail sample code.

Amir Kashani

unread,
Oct 24, 2010, 4:16:19 AM10/24/10
to Google Web Toolkit
Moe,

Are you using PlaceHistoryMapperWithFactory? If so, my best guess is
that you're forgetting to call setFactory in your onModuleLoad():

AppPlaceHistoryMapper historyMapper =
GWT.create(AppPlaceHistoryMapper.class);
historyMapper.setFactory(ginjector.getAppPlaceFactory());

If that's not it, take a look at the generated code to see if you can
figure out what exactly is null on that line (-gen compiler option).

HTH.

- Amir

moejo

unread,
Oct 24, 2010, 7:56:19 AM10/24/10
to Google Web Toolkit
Hi Amir,

Yes, your absolutely right - forgot to call setFactory! Now
everything is working stunningly. I've put together a sample bit of
code using the Contact Details code I mentioned previously and it can
be downloaded at:

http://www.bright-creations.com/wp-content/uploads/2010/10/ContactsClientFactoryGin3-export.zip

If you guys have any comments about the code, please let me know.
Thanks for all your advice, you guys have been seriously helpful.

Cheers

Moe

moejo

unread,
Oct 24, 2010, 8:43:35 AM10/24/10
to Google Web Toolkit
By the way, something I realised that although we can't map a 1-Many
relationship between a Place and an Activity, you can in fact map
multiple places to the same activity and differentiate between the
place with multiple init() methods in the activity.

On Oct 24, 1:56 pm, moejo <mahamad.el.tan...@gmail.com> wrote:
> Hi Amir,
>
> Yes, your absolutely right - forgot to call setFactory!  Now
> everything is working stunningly.  I've put together a sample bit of
> code using the Contact Details code I mentioned previously and it can
> be downloaded at:
>
> http://www.bright-creations.com/wp-content/uploads/2010/10/ContactsCl...

zixzigma

unread,
Nov 17, 2010, 12:19:18 AM11/17/10
to Google Web Toolkit

in the following code fragment posted:

> @Override
> public Activity getActivity(Place place) {
> if (place instanceof HelloPlace) {
> return injector.getHelloActivity().withPlace((HelloPlace)


injector.getHelloActivity().withPlace((HelloPlace)


could you please explain this "withPlace" bit ?

injector.getHelloActivity(), gives you the interface
but how can you chain it with "withPlace( .,, )" ?

is it some custom code you wrote ?

Thank You

zixzigma

unread,
Nov 17, 2010, 12:24:13 AM11/17/10
to Google Web Toolkit
gives you the Activity*

Frank Bølviken

unread,
Dec 23, 2010, 3:31:50 AM12/23/10
to Google Web Toolkit
Hi,

Have you written any tests for this? Im curious about the testing
abilities of a GWT app which uses GIN etc using EasyMock or Mockito or
something.
I've been told that it's very easy to test with Junit tests.. is this
the case? Do you have any examples?

Thanks in advance,
Frank B

On Oct 24, 12:56 pm, moejo <mahamad.el.tan...@gmail.com> wrote:
> Hi Amir,
>
> Yes, your absolutely right - forgot to call setFactory!  Now
> everything is working stunningly.  I've put together a sample bit of
> code using the Contact Details code I mentioned previously and it can
> be downloaded at:
>
> http://www.bright-creations.com/wp-content/uploads/2010/10/ContactsCl...

VA

unread,
Jan 31, 2011, 5:14:35 AM1/31/11
to google-we...@googlegroups.com
This works absolutly fine for single display view.
How can I use this for a multi displau view?  
 
Thanks.
Reply all
Reply to author
Forward
0 new messages