I am using the GWT Activities and Places framework to structure my application and it is turning out nicely. One thing that annoys me though is that the ActivityMapper
implementation is (1) receiving all the views in the application (2) contains a giant if/else block for instantiating activities based on the received place. It will only get worse as the number of views increases.
I am already using Gin but I don't see how I can use it here.
How can I reduce or eliminate the boilerplate from my ActivityMapper
?
One possibility is to have the root of your Place class hierarchy define a createActivity() method, and Place subclasses can return a new instance of the Activity they're associated with.
This has the advantage of having eliminated that if/else block, and having one less place to modify when you add a new Place/Activity. The downside of this is that it kindof pollutes your Place class with Activity creation behavior, even if you're just delegating to a Ginjector.
There isn't a great answer yet. I have code generation schemes in mind, but it's all scribbles on white boards at the moment. For Gin users it seems like a Place Scope might be handy.
Re: the if / else cascade, one common approach is to make your Place objects implement the visitor pattern. E.g. let's assume you have AssistedInject set up for your activities (and forgive the sloppy field injection, it's just a sketch).
Just for future reference for people like me landed here and still have no answer. I´ve ended up with the following solution using GIN and Generators for a PlaceFactory.
This is what my tokens look like now. eg: #EditUser/id:15/type:Agent
I have a AbstractPlace that every Place should extend from.
An example Place:
PlaceFactory interface for Defered binding:
and a annotation for registering place classes
and the PlaceFactoryGenerator
Setup the generator in you GWT Module
Whats my ActivityMapper look like?
We need a custom PlaceHistoryMapper
And at last the PlaceFactory, this will be generated for just put your place classes in the annotation and be happy!
I found a neat approach by Igor Klimer. He uses the visitor pattern to push the decision logic into the Place implementation, that way the ActivityMapper stays quite simple. Check out his blog post for implementation details.
Actually I am using custom boilerplate code for this task:
}
Where ActivityContainer is a simple factory type (from this point classic ioc methods can be used).
Of course now it is only changing 'if block' with a map lookup/population, but combined with Gin multibinding (witch currently does not exist) could do it's job.
Also Gin enhancement - generic GinModule for GWT Activity/Places looks promising.
First of all I created an issue on GWT issuesfor this so please star it and or comment on it. Here's how I do it:
Then in your ActivityMapper:
All of your places should extend PlaceWithActivity. The only issue is the down-casting which risks a ClassCastException. Place had the getActivity() then you wouldn't have to downcast but it doesn't so you have to downcast it to a class that does.
What I don't like about it is that you have to do casting and make the PlaceWithActivity class. This wouldn't be necessary, if GWT would add support for what I'm doing. If they included a PlaceWithActivity class you wouldn't have to make it and if the ActivityManager would just call the getActivity() method of the PlaceWithActivity class then you would not only not have to down cast, but you wouldn't even need to write the ActivityMapper!