Wicket RAD and wicket-guice on Wicket 1.4

View: New views
7 Messages — Rating Filter:   Alert me  

Wicket RAD and wicket-guice on Wicket 1.4

by oyvindj :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

As the topic of Wicket-RAD and Guice (superb lightweight dependency injection with type safety and annotations) came up on Twitter I will continue the discussion here...

Regarding using Wicket-RAD with wicket-guice on Wicket 1.4, there is really not much Wicket-RAD specific to say. I have been using this combination for a while and the only requirement is that Wicket-RAD is compiled with Wicket 1.4. Otherwise you will get runtime error since some Wicket base class has changed from 1.3.

Below is the relevant part from the application init() method from one of my applications. I am also using Guice and Wicket with Warp-Persist. An annotation based persistence framework combining Guice and Hibernate annotations with some cool features (hint DynamicFinders... ++ ).

        @Override
        protected void init()
        {
                log.trace("entering Application.init()...");
               
                /*
                 * Setting up Warp persistence w/ Hibernate
                 */
                injector = Guice.createInjector(
                                PersistenceService
                                        .usingHibernate()
                                        .across(UnitOfWork.REQUEST)
                                        .transactedWith(TransactionStrategy.LOCAL)
                                        .addAccessor(DataAccessorService.class)
                                        .buildModule(),
                                        new GuiceModule());
               
                // enabling Guice for Wicket applicatation
                addComponentInstantiationListener(new GuiceComponentInjector(this, injector));

                PersistenceService persistenceService = injector.getInstance(PersistenceService.class);
                persistenceService.start();
               
                injector.injectMembers(this);

What is happening is that You first create an injector by passing the "createInjector" method of Guice two Guice modules. The first module is the a Warp-Persist persistence module, the second module is our application's Guice configuration class.

Second we add a component instatiation listener to our application. This makes sure that Guice gets a chance to inject objects when our wicket objects are instantiated by the application.

Third the Warp-Persist service is started.

Last I tell the injector to inject members into the application class itself. I believe this is only required if you need to inject something into the application object itself.

Regards,
Oyvind
 

Re: Wicket RAD and wicket-guice on Wicket 1.4

by oyvindj :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I realized that there is probably at least one way support for Guice will have to be supported by Wicket RAD in a similar way that Wicket does.

This is when objects that will be instantiated by wicket-rad are using injected objects. This could in theory be several types of objects.

The one example I have run into is for the different Choice classes where you often wants to call a service layer object to retrieve the options to return. In this case you typically want to inject this service object.

I believe this needs to be supported by the framework (wicket-rad) somehow (maybe through a component instantation listener) to avoid ugliness. I use some some ugly hack to work around this problem currently.

It could also be that I am totally wrong and there is an easy way around the issue that I don't know about...

Oyvind

Re: Wicket RAD and wicket-guice on Wicket 1.4

by wfaler :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Agree, there is no need to do much more integration with Guice for components than what has already been done with the Wicket Guice extensions instantiation listener.

However it makes sense for the "data retrievers and populators" in Wicket RAD, such as IChoiceSource et al.

One thought I had was for instance when you annotate something with @DropDownChoice(MyChoiceSource.class), we could instantiate it from the implementation class if MyChoiceSource is an actual implementation class, whereas if it is simply an interface extending IChoiceSource we can delegate the instantiation to Guice.

This would probably mean that you could only map interface -> impl in Guice, but I think that would be good enough, as your interfaces would for the most part only be "marker interfaces" for Guice and Wicket RAD.

What do you think, does it make sense?

The other question of course is whether or not to put the Guice dependency in the core framework, I'm thinking "no", but at the same time the implementation classes for generation (at least by annotation) are in the core, and would almost have to be Guice aware, so maybe having a Guice jar dependency wouldn't be the end of the world, so long as it is not forced on them to actually use.

/ Wille

oyvindj wrote:
I realized that there is probably at least one way support for Guice will have to be supported by Wicket RAD in a similar way that Wicket does.

This is when objects that will be instantiated by wicket-rad are using injected objects. This could in theory be several types of objects.

The one example I have run into is for the different Choice classes where you often wants to call a service layer object to retrieve the options to return. In this case you typically want to inject this service object.

I believe this needs to be supported by the framework (wicket-rad) somehow (maybe through a component instantation listener) to avoid ugliness. I use some some ugly hack to work around this problem currently.

It could also be that I am totally wrong and there is an easy way around the issue that I don't know about...

Oyvind

Re: Wicket RAD and wicket-guice on Wicket 1.4

by wfaler :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

There is now an experimental implementation available in SVN for IChoiceSource based injection.

It works as described in my previous post: if the IChoiceSource class given in an annotation is an impl, it works "as before", if it is an interface it will go to Guice to get an implementation (which can have stuff injected into it as per Guice).

You have to add a ComponentInstantiationListener in your Applications init()-method just as you would with GuiceComponentInjector.
In fact, I have created a class called RadGuiceComponentInjector which is a direct extension of org.apache.wicket.guice.GuiceComponentInjector that you should use (only main difference is that it has one less constructor, loosing the single argument constructor).

I'm not sure whether Injector in Guice is thread-safe, do you have any idea about this? This is the "gotcha" I am yet to work out..

Re: Wicket RAD and wicket-guice on Wicket 1.4

by oyvindj :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

What you are suggesting was the first idea that occurred to me as well. I immediately checked if you supported interface instead of a class there somehow...

Then you can throw an exception stating something like "extension required for use of interfaces..." in case the extension is not on the classpath.

But you do have another problem to solve. In order to inject the right class Wicket-RAD need access to the Guice injector.

This probably means that on startup of the wicket application the injector that is created would have to be passed to wicket-rad and stored somehow for the liftetime of the application... Do you have any such "init process" in your framework that can be extended to support this maybe...

This would be equivalent to doing what you saw in my Application init(), where the injector is passed to the framework by passing in an extension specific object that implements a framework interface:

WICKET-FRAMEWORK.addComponentInstantiationListener(
    new WICKET-GUICE-EXTENSION.GuiceComponentInjector(this, INJECTOR)
);

I would imagine this could be solved in Wicket RAD with something like:

WICKET-RAD-FRAMEWORK.addGuiceSupport(
    new WICKET-RAD-GUICE-EXTENSION.GuiceComponentInjector(this ???, INJECTOR)
);

The problem being, what is the class/object that represents WICKET-RAD-FRAMEWORK in the example above?

I don't know how closely you have looked at Guice... the more the higher chance this makes any sense to you I guess... I belive this is a generic problem when you want a framework or submodule to take advantage of logic in a parent module without polluting the APIs by passing around the objects...

What do you think?

Oyvind


 


wfaler wrote:
Agree, there is no need to do much more integration with Guice for components than what has already been done with the Wicket Guice extensions instantiation listener.

However it makes sense for the "data retrievers and populators" in Wicket RAD, such as IChoiceSource et al.

One thought I had was for instance when you annotate something with @DropDownChoice(MyChoiceSource.class), we could instantiate it from the implementation class if MyChoiceSource is an actual implementation class, whereas if it is simply an interface extending IChoiceSource we can delegate the instantiation to Guice.

This would probably mean that you could only map interface -> impl in Guice, but I think that would be good enough, as your interfaces would for the most part only be "marker interfaces" for Guice and Wicket RAD.

What do you think, does it make sense?

The other question of course is whether or not to put the Guice dependency in the core framework, I'm thinking "no", but at the same time the implementation classes for generation (at least by annotation) are in the core, and would almost have to be Guice aware, so maybe having a Guice jar dependency wouldn't be the end of the world, so long as it is not forced on them to actually use.

/ Wille

Re: Wicket RAD and wicket-guice on Wicket 1.4

by wfaler :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

What I have done (read my previous post, but lower in the thread from what you answered to) is pretty close to what you are stating, but simply by extending the GuiceComponentInjector instantiation listener.

If one has not been been added to the Application, an IllegalStateException with an explanation will be thrown (saying "Guice support must be installed for instantiation by interface bla bla bla").


Hi,

What you are suggesting was the first idea that occurred to me as well. I immediately checked if you supported interface instead of a class there somehow...

Then you can throw an exception stating something like "extension required for use of interfaces..." in case the extension is not on the classpath.

But you do have another problem to solve. In order to inject the right class Wicket-RAD need access to the Guice injector.

This probably means that on startup of the wicket application the injector that is created would have to be passed to wicket-rad and stored somehow for the liftetime of the application... Do you have any such "init process" in your framework that can be extended to support this maybe...

This would be equivalent to doing what you saw in my Application init(), where the injector is passed to the framework by passing in an extension specific object that implements a framework interface:

WICKET-FRAMEWORK.addComponentInstantiationListener(
    new WICKET-GUICE-EXTENSION.GuiceComponentInjector(this, INJECTOR)
);

I would imagine this could be solved in Wicket RAD with something like:

WICKET-RAD-FRAMEWORK.addGuiceSupport(
    new WICKET-RAD-GUICE-EXTENSION.GuiceComponentInjector(this ???, INJECTOR)
);

The problem being, what is the class/object that represents WICKET-RAD-FRAMEWORK in the example above?

I don't know how closely you have looked at Guice... the more the higher chance this makes any sense to you I guess... I belive this is a generic problem when you want a framework or submodule to take advantage of logic in a parent module without polluting the APIs by passing around the objects...

What do you think?

Oyvind


 


wfaler wrote:
Agree, there is no need to do much more integration with Guice for components than what has already been done with the Wicket Guice extensions instantiation listener.

However it makes sense for the "data retrievers and populators" in Wicket RAD, such as IChoiceSource et al.

One thought I had was for instance when you annotate something with @DropDownChoice(MyChoiceSource.class), we could instantiate it from the implementation class if MyChoiceSource is an actual implementation class, whereas if it is simply an interface extending IChoiceSource we can delegate the instantiation to Guice.

This would probably mean that you could only map interface -> impl in Guice, but I think that would be good enough, as your interfaces would for the most part only be "marker interfaces" for Guice and Wicket RAD.

What do you think, does it make sense?

The other question of course is whether or not to put the Guice dependency in the core framework, I'm thinking "no", but at the same time the implementation classes for generation (at least by annotation) are in the core, and would almost have to be Guice aware, so maybe having a Guice jar dependency wouldn't be the end of the world, so long as it is not forced on them to actually use.

/ Wille


Re: Wicket RAD and wicket-guice on Wicket 1.4

by oyvindj :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

ops.. should have updated thread before posting...

sounds perfect! ...I underestimated the powers of that instantiation listener...

btw. I listened to a podcast by Bob Lee (Guice creator) yesterday. For the next version of Guice it sounds like there will be greater support for such things as sharing the guice configuration between modules/layers.

The example he came up what was the classical web/service layer case.

Great job!

Oyvind