this is nice.

what i do like about it
* you can inject anything anywhere

what i dont like is
* post constructor injection like youve mentioned - delegate or not it still
sucks, a different pointcut is needed
* you have to keep your variables transient - very easy mistake to make,
otherwise big boo boo might happen if the dependency is serializable and you
wont know until much later
* you have to inject everything - ie i cant take an instance of injected
service and pass it to some other component to use
* i dont like @Configure on the entire object, i like per-field annotations
on the fields
* you have to have access to the java runtime args to install the weaver

what is needed to fix this
* a different aspect that wraps the bean in the wicket-proxy just like we do
now - that should give you the ultimate freedom, but then what worries me is
if tomcat will let you cluster objects loaded through aspectj classloader.

-Igor



Leszek Gawron-2 wrote:
> 
> Hello,
> I just wanted to share another way of injecting spring services into 
> wicket code. This one uses AOP.
> 
>             - o - Why another approach? - o -
> 
> Using wicket-spring along with wicket-spring-annot works nicely for 
> components (althought you have to remember not initializing it yourself) 
> but does not work for other parts of application - models. Just ask your 
> self how many times you have put a spring service into wicket page only 
> to pass it to model constructed:
> 
>> public class RankingPanel extends Panel {
>>     @SpringBean
>>     private LeagueService leagueService;
>> 
>>     public RankingPanel( String id, IModel leagueModel ) {
>>         super( id );
>>         add( new ListView( "ranking", new RankingModel( leagueService,
>> leagueModel ) ) {
>>             @Override
>>             protected void populateItem( ListItem listItem ) {
>>                 PlayerRank rank = (PlayerRank) listItem.getModelObject();
>>                 listItem.add( new Label( "position", String.valueOf(
>> rank.getPosition() ) ) );
>>                 listItem.add( new Label( "player",
>> rank.getPlayer().getFullName() ) );
>>             }
>>         } );
>>     }
>> }
> 
> If you could have your model injected with appropriate service this 
> would probably be:
> 
>> public class RankingPanel extends Panel {
>>     public RankingPanel( String id, IModel leagueModel ) {
>>         super( id );
>>         add( new ListView( "ranking", new RankingModel( leagueModel ) ) {
>>             @Override
>>             protected void populateItem( ListItem listItem ) {
>>                 PlayerRank rank = (PlayerRank) listItem.getModelObject();
>>                 listItem.add( new Label( "position", String.valueOf(
>> rank.getPosition() ) ) );
>>                 listItem.add( new Label( "player",
>> rank.getPlayer().getFullName() ) );
>>             }
>>         } );
>>     }
>> }
> 
>             - o - What you'll need - o -
> 
> - your current fancy project
> - one fresh spring (at least 2.0 M1). I have used 2.0-rc2.
> - one ripe aspectj (http://ibiblio.org/maven2/aspectj/) especially
>    aspectjrt and aspectjweaver. I have used 1.5.2.
> - java 1.5 (there are probably some ways to do it with 1.4 - didn't 
> bother to try)
> 
>             - o - Implementation - o -
> 
> Spring 2.0 M1 introduced @Configurable annotation [1]. We can use it to 
> inject spring beans into ANY object (not only created by spring but also 
> simply instantiated with new MyObject() ).
> 
> Let's create a simple spring context:
> 
>> <?xml version="1.0" encoding="UTF-8"?>
>> <beans xmlns="http://www.springframework.org/schema/beans";
>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>>     xmlns:aop="http://www.springframework.org/schema/aop";
>> xmlns:tx="http://www.springframework.org/schema/tx";
>>     xsi:schemaLocation="
>>     http://www.springframework.org/schema/beans
>> http://www.springframework.org/schema/beans/spring-beans.xsd
>>     http://www.springframework.org/schema/tx
>> http://www.springframework.org/schema/tx/spring-tx.xsd
>>     http://www.springframework.org/schema/aop
>> http://www.springframework.org/schema/aop/spring-aop.xsd";>
>>     <bean
>> class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
>>     
>>     <aop:spring-configured/>
>>     
>>     <bean id="leagueService"
>> class="com.mobilebox.squasher.service.impl.LeagueServiceImpl
>> autowire="byName"/>
>> </beans>
> 
> We have a single service declared here. What's more important is 
> <aop:spring-configured/> which simply saying turns on Spring AspectJ 
> machinery. Please refer to [1] for additional info.
> 
> Now let's build a wicket model:
> 
>> @Configurable(autowire = Autowire.BY_NAME, dependencyCheck = true)
>> public class RankingModel extends LoadableDetachableModel {
>>     protected transient LeagueService   leagueService;
>> 
>>     public void setLeagueService( LeagueService leagueService ) {
>>         this.leagueService = leagueService;
>>     }
>> 
>>     public RankingModel( IModel master ) {
>>         this.master = master;
>>     }
>> 
>>     @SuppressWarnings("unchecked")
>>     @Override
>>     protected Object load() {
>>         return new LinkedList( leagueService.getRanking(
>> leagueService.loadRound( (Long) master.getObject( null ) ) ) );
>>     }
>> }
> 
> Nothing shocking. Just remember to annotate your class with 
> @Configurable and make your reference to LeagueService transient.
> 
> You need to put an additional file on the classpath to make it all work. 
> The location should be META-INF/aop.xml. Mine states:
> 
>> <aspectj>
>>     <weaver options="-showWeaveInfo
>> -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler">
>>         <include within="com.mobilebox.squasher..*"/>
>>     </weaver>
>>     <aspects>
>>         <include
>> within="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
>>     </aspects>
>> </aspectj>
> 
> You can drop aspectj/weaver/@options. This is only for debugging 
> purposes. Remember to change aspectj/weaver/include/@within attribute to 
>   match the package (and subpackages) you want weaved.
> 
> That's all for coding. Let's run it.
> 
>             - o - Running - o -
> 
> Put aspectjrt.jar on classpath. Create you JVM with additional option 
> (adjust aspectjweaver location):
> 
>> java -javaagent:lib/aspectjweaver.jar
>> com.mobilebox.squasher.launcher.JettyRunner
> 
> If you run your container from withing Eclipse IDE put 
> '-javaagent:lib/aspectjweaver.jar' in 'VM arguments' editbox.
> 
> That's all. AspectJ will weave your RankingModel class on load and 
> inject leagueService reference. In case of my project that was starting 
> in 5.5 seconds it added 2 more seconds. You can skip Load-Time Weaving 
> (LTW) if you just used aspectj compiler or weaved your classes offline.
> 
>             - o - Serialization - o -
> 
> Exactly. Wicket is know with it's I-serialize-everything-like-crazy. 
> Turns out this is already handled. You need to make references to your 
> services *transient* so they are not serialized. Fortunately when 
> deserializing and object from stream AOP also kicks in so you have your 
> service reference reinjected. Pure fun!
> 
>             - o - Gotchas - o -
> Every programming solutions got one. This one also. With current 
> @Configurable implementation services get injected AFTER the injectee is 
> created (after all constructors got invoked). That means this won't work:
> 
>> public class LeaguePage extends BaseSquasherPage {
>>     private LeagueService   leagueService;
>> 
>>     public LeaguePage( PageParameters parameters ) throws
>> StringValueConversionException {
>>         Long leagueId = parameters.getLong( "id" );
>> 
>>         // nasty NPE here!
>>         League league = leagueService.loadLeague( leagueId );
>> 
>>         add( new Label( "leagueName", league.getName() ) );
>>     }
>> }
> 
> You can do 2 things:
> - implement another AOP pointcut so services get injected before 
> construction (do not know if that is possible, will dig further)
> - be smarter than AOP itself:
> 
>> @Configurable(autowire = Autowire.BY_NAME, dependencyCheck = true)
>> public class LeagueServiceDelegate implements Serializable, LeagueService
>> {
>>     private transient LeagueService leagueService;
>> 
>>     public void setLeagueService( LeagueService leagueService ) {
>>         this.leagueService = leagueService;
>>     }
>> 
>>     public League loadLeague( Long id ) {
>>         return leagueService.loadLeague( id );
>>     }
>> }
> 
>> public class LeaguePage extends BaseSquasherPage {
>>     private LeagueServiceDelegate   leagueService = new
>> LeagueServiceDelegate();
>> 
>>     public LeaguePage( PageParameters parameters ) throws
>> StringValueConversionException {
>>         Long leagueId = parameters.getLong( "id" );
>> 
>>         // the delegate is already up and running
>>         League league = leagueService.loadLeague( leagueId );
>> 
>>         add( new Label( "leagueName", league.getName() ) );
>>     }
>> }
> 
> With eclipse you can create such delegate in 30 seconds no matter how 
> big the target service is. (generate setter, generate delegates).
> 
>             - o - Post scriptum - o -
> 
> If anyone is interested I will blogify this entry along with sample 
> working project to test. Just let me know.
> 
> [1] 
> http://www.springframework.org/docs/reference/aop.html#aop-atconfigurable
> 
> -- 
> Leszek Gawron
> 
> -------------------------------------------------------------------------
> Take Surveys. Earn Cash. Influence the Future of IT
> Join SourceForge.net's Techsay panel and you'll get the chance to share
> your
> opinions on IT & business topics through brief surveys -- and earn cash
> http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
> _______________________________________________
> Wicket-user mailing list
> Wicket-user@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/wicket-user
> 
> 

-- 
View this message in context: 
http://www.nabble.com/-tutorial--Wicket-%2B-Spring-integration---revisited-tf2375652.html#a6622688
Sent from the Wicket - User mailing list archive at Nabble.com.


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Wicket-user mailing list
Wicket-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wicket-user

Reply via email to