How to avoid specifing a tokenizer for each place

272 views
Skip to first unread message

Daniel Guggi

unread,
Aug 24, 2011, 3:53:04 AM8/24/11
to google-we...@googlegroups.com
hi,

suppose I have an application which consists of serveral modules like
- main
- moduleA
- moduleB
- etc.

the "main"-module defines the main layout and sets up "activity mappers", the "PlaceHistoryMapper" and so on.
the other modules like "moduleA", "moduleB" etc. define their own set of activities and places.

I'm wondering how I can define new places in "moduleA" and "moduleB" without changing the "PlaceHistoryMapper" in the "main"-module (e.g. adjusting the @WithTokenizers-annotation)?
I don't see that the PlaceHistoryMapperWithFactory can help here, since I still have to adjust the "main"-module?

are there any approaches to this? Could I use a custom generator (in the main-module) that for instance finds all types of "MyAppTokenizer" and creates a PlaceHistoryMapper accordingly?

tia,
daniel

Daniel Guggi

unread,
Aug 24, 2011, 11:31:28 AM8/24/11
to google-we...@googlegroups.com
To summarize my goal:
- I don't want a central place where I have to summarize all tokenizers in my application.
E.g. When I add a new place and an appropriate tokenizer I HAVE to specifiy the tokenizer using the @WithTokenizers annotation
- Later I would also like to remove the "instanceof" boilterplate from my ActivityMappers (using a generator)

Imo one solution would be to create a custom generator (similar to gwt's PlaceHistoryMapperGenerator) as follows:

- I can add some custom annotation lets say @AppTokenizer and annotate every implementation of PlaceTokenizer in my app
- The generator can than create a class which resolves all PlaceTokenizers with that annotation

my concern is that: in order to find all PlaceTokenizer if have to to something like this in my generator:

JClassType[] types = typeOracle.getTypes();
        for (JClassType type : types) {
            if (type.getAnnotation(SomeAnnotation.class) != null) {
                //some more stuff here               
            }
        }

So the generator loops through *all* available types to find the appropriate tokenizers to be used.
This may be slow - is this the reason why we have to summarize all Tokenizers (Using @WithTokenizer annotation) in the gwt standard approach?
Are there any better ways to achieve such functionality?

tia,
daniel

Thomas Broyer

unread,
Aug 24, 2011, 11:48:12 AM8/24/11
to google-we...@googlegroups.com
The issue is to detect conflicts (no two tokenizers can use the same @Prefix, so everything must be known at compile-time, and because everything is done by code-analysis, your "root" PlaceHistoryMapper then has to "define" all of the tokenizers)

I believe you could do it with a factory, if you define one interface per module, and then use a factory that implements all of them at once (you can use a interface and have its implementation be generated, and you could also simply make it a Ginjector and have GIN be the generator).

In case that wouldn't work (or you wouldn't like it), how about:
  1. have a distinct PlaceHistoryMapper per module
  2. have your "root" PlaceHistoryMapper aggregating all of them, calling them in turn until one answers with a non-null value (chain of responsibility pattern, kind of)
That wouldn't detect conflicts in prefixes though, so it will be up to you to do it manually (or with an automated test exercising all of them).

Daniel Guggi

unread,
Aug 24, 2011, 12:15:07 PM8/24/11
to google-we...@googlegroups.com
thomas thank you for your input!

@"I believe you could do it with a factory, if you define one interface per module, and then use a factory that implements all of them at once (you can use a interface and have its implementation be generated, and you could also simply make it a Ginjector and have GIN be the generator)."

I don't really understand your idea - can you please clarify?  I use GIN but how will GIN generate an implementation of an "custom" interface - there has to be some sort of generator i think?

Thank you,
daniel


--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/M3rpiPNC65EJ.
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.

Thomas Broyer

unread,
Aug 24, 2011, 3:31:00 PM8/24/11
to google-we...@googlegroups.com
Something like:

interface FooFactory {
  APlace.Tokenizer fooA();
  BPlace.Tokenizer fooB();
}

interface BarFactory {
  CPlace.Tokenizer barC();
  DPlace.Tokenizer barD();
}

interface MainFactory extends Ginjector, FooFactory, BarFactory {
}

interface MainPlaceHistoryMapper extends PlaceHistoryMapperWithFactory<MainFactory> {
}

MainFactory is a Ginjector, so GIN will generate it's implementation. If your PlaceTokenizer-s are default-instantiable (as they would have to be if used with @WithTokenizers), then you don't even need a GinModule.

Daniel Guggi

unread,
Aug 25, 2011, 2:39:40 AM8/25/11
to google-we...@googlegroups.com
right, now i got it :)

I'll give it a try, thanks thomas!

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

Daniel Guggi

unread,
Aug 25, 2011, 4:48:00 AM8/25/11
to google-we...@googlegroups.com
I have the following:

public interface ModuleAFactory {
   APlace.Tokenizer getTokenizer1();
}

public interface ModuleBFactory {
   BPlace.Tokenizer getTokenizer1();
}

public interface MainFactory extends Ginjector, ModuleAFactory, ModuleBFactory {
}

public interface MyPlaceHistoryMapper extends PlaceHistoryMapper<MainFactory>{
}


I understand how stuff (gwt-generator and GIN play together). As i mentioned I'm already using GIN in my application like this:

@GinModules({GwtAppModule.class})
public interface GwtAppGinjector extends Ginjector {  
    PlaceHistoryHandler getPlaceHistoryHandler();
    ApplicationLayout getApplicationLayout();
}


Now in my GwtAppModule.java i have added the following two methods in order to create the PlaceHistoryMapper incl. MainFactory(Ginjector) and the PlaceHistoryHandler.

    @Singleton @Provides
    public PlaceHistoryMapper getHistoryMapper() {
        MainFactory factory = GWT.create(MainFactory.class); // create MainFactory-Ginjector
        PlaceHistoryMapperWithFactory<MainFactory> mapper = GWT.create(MyPlaceHistoryMapper.class);
        mapper.setFactory(factory);
        return mapper;
    }
   
    @Singleton @Provides
    public PlaceHistoryHandler getHistoryHandler(PlaceController placeController, PlaceHistoryMapper historyMapper, EventBus eventBus) {
        PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
        historyHandler.register(placeController, eventBus, new InvoiceOverviewPlace());
        return historyHandler;
    }


As far as I understand, I'm creating a the MainFactory-Ginjector from ?within? another Ginjector (GwtAppGinjector). I'm wondering if this is a legitim approach or if there are better ways (best-practice) to do this?

tia,
daniel
Reply all
Reply to author
Forward
0 new messages