Igor and all --

I also had this problem when using default constructor and initialization by properties.

OTOH I have Hibernate DAO classes using transactions, and they work fine.

Good news, the problem went away when I broke the Bean1->Bean2 chain because of application reasons. If/when the problem reappears, I will try to report in more detail.

Thanks everyone for your help,
-- Sasha

Igor Vaynberg wrote:
this isnt really wicket-specific. this is just something you need to
be aware of when dealing with IOC containers. if you wanted to eg have
transactional methods on this bean you would run into the same problem
as spring would try to create a proxy of your class to manage
transactions (unless you were using direct bytecode weaving...)

-igor

On Sun, Aug 31, 2008 at 6:45 PM, Sasha Ovsankin
<[EMAIL PROTECTED]> wrote:
Cemal --

Thanks, the trace indeed looks familiar. I will try the suggestion to make
Bean2 an interface. I will also try to distill a test from this problem.

Will let you know.

Thanks,
-- Sasha

jWeekend wrote:
Sasha,

Does the trace at the end of this note, in my PS, look familiar?
Now try the following code (notice the addition and use of the IBean2
interface) - things should work once you make the type of the reference in
your component (a Page in this case) the interface. If you can't do that
on
your project (eg Bean2 is from a 3rd party library) then we'll have to
take
another look.
Does that help?

     <bean id="bean1" class="scratch.springbean.Bean1"/>
   <bean id="bean2" class="scratch.springbean.Bean2"><constructor-arg
ref="bean1"/></bean>
===
public class SpringBeanPage extends WebPage{
   @SpringBean IBean2 bean2;
   public SpringBeanPage() {
       add(new Label("sprung",bean2.getBean1().name));
   }   }
====
public class Bean1 {
   public String name;
   @Override
   public String toString() {
       return name;
   }
}
===
public class Bean2 implements IBean2 {
   public Bean1 bean1;
   protected Bean2(Bean1 bean1) {
       super();
       this.bean1 = bean1;
       bean1.name = "Sprung";
   }
   public Bean1 getBean1() {
       return bean1;
   }
   public void setBean1(Bean1 bean1) {
       this.bean1 = bean1;
   }
}

Regards - Cemal
http://www.jWeekend.co.uk http://jWeekend.co.uk
PS Is this similar to the exception you saw?
org.apache.wicket.WicketRuntimeException: Can't instantiate page using
constructor public scratch.springbean.SpringBeanPage()
       at

org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:168)
       at

org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:58)
       at

org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.newPage(BookmarkablePageRequestTarget.java:262)
       at

org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.getPage(BookmarkablePageRequestTarget.java:283)
       at

org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.processEvents(BookmarkablePageRequestTarget.java:210)
       at

org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:91)
       at

org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1166)
       at org.apache.wicket.RequestCycle.step(RequestCycle.java:1243)
       at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1331)
       at org.apache.wicket.RequestCycle.request(RequestCycle.java:493)
       at
org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:363)
       at

org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:194)
       at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
       at

org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:112)
       at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
       at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
       at
org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
       at

org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
       at
org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
       at
org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
       at
org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
       at
org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
       at org.mortbay.jetty.Server.handle(Server.java:324)
       at
org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
       at

org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:828)
       at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
       at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
       at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
       at

org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
       at

org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:450)
Caused by: java.lang.reflect.InvocationTargetException
       at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method)
       at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown
Source)
       at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown
Source)
       at java.lang.reflect.Constructor.newInstance(Unknown Source)
       at

org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:149)
       ... 29 more
Caused by: java.lang.RuntimeException: error while injecting object [[Page
class = scratch.springbean.SpringBeanPage, id = 0, version = 0]] of type
[scratch.springbean.SpringBeanPage]
       at org.apache.wicket.injection.Injector.inject(Injector.java:118)
       at

org.apache.wicket.injection.ConfigurableInjector.inject(ConfigurableInjector.java:39)
       at

org.apache.wicket.injection.ComponentInjector.onInstantiation(ComponentInjector.java:52)
       at

org.apache.wicket.Application.notifyComponentInstantiationListeners(Application.java:974)
       at org.apache.wicket.Component.<init>(Component.java:873)
       at
org.apache.wicket.MarkupContainer.<init>(MarkupContainer.java:105)
       at org.apache.wicket.Page.<init>(Page.java:236)
       at org.apache.wicket.markup.html.WebPage.<init>(WebPage.java:184)
       at scratch.springbean.SpringBeanPage.<init>(SpringBeanPage.java:9)
       ... 34 more
Caused by: java.lang.IllegalArgumentException: Superclass has no null
constructors but no arguments were given
       at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:718)
       at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499)
       at

net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
       at

net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
       at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
       at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
       at

org.apache.wicket.proxy.LazyInitProxyFactory.createProxy(LazyInitProxyFactory.java:173)
       at

org.apache.wicket.spring.injection.annot.AnnotProxyFieldValueFactory.getFieldValue(AnnotProxyFieldValueFactory.java:101)
       at org.apache.wicket.injection.Injector.inject(Injector.java:108)
       ... 42 more



Sasha Ovsankin wrote:
Igor --

Here is what I had:

       class Bean1 {...}

        class Bean2 {
          public Bean2(Bean1 bean1) {}
        }

       Spring config:

       <bean name="bean1" class="Bean1"/>
       <bean name="bean2" class="Bean2">
         <constructor-arg name="bean1" ref="bean1"/>
       </bean>

       class MyPanel extends Panel {
         ...
         @SpringBean Bean2 bean2;
         ...
       }

The problem was that bean2 could not initialize, it was looking for empty
constructor which the class didn't have and failed. I tried using property
initialization but ended up with null value for Bean1 and methods of bean2
were failing with NPE.

I had another group of beans like that in the program which was working
fine.

Another thing that got me scared was that the initializer for Bean1 got
called twice: once on application initialization and once on initialization
of the page. I spent some time within initialization code, CGLib and such
and figured I needed much more time to figure out what's happening there.

I will report more on this problem when I have time to assemble test
case. I have workaround now and I am on to the next problem -- see my
separate email.

Thanks,
-- Sasha

Igor Vaynberg wrote:
On Sun, Aug 31, 2008 at 3:44 PM, Sasha Ovsankin
<[EMAIL PROTECTED]> wrote:
You may end up with a solution that is quite convoluted, hard to
learn/maintain, less elegant and hard to get just right in all cases
(for
example testing, serialization/deserialisation etc...).
We will see, but so far I have a solution that is under 100 LOC, works
for
me and saves me from debugging in the internals of CGLib.
how does springbean require you to debug cglib internals?

Locatable<MyDAO> dao= new Locatable<MyDAO>("myDAO", MyDAO.class);
Locatable<MyDAO2> dao= new Locatable<MyDAO2>("myDAO2", MyDAO2.class);

vs

@SpringBean MyDAO dao;
@SpringBean MyDAO2 dao2;

i still like springbean :) also, considering most of the frameworks
use cglib anyways (spring, hibernate, etc) you dont really win
anything...

-igor



I will still report the parent problem when I have time to compose a
test
case.

Thanks for your feedback,
-- Sasha

jWeekend wrote:
If you mark that DAO as transient, what will happen after
deserialising
your
page? Will you implement your own serialisation strategy to go with
your
home-made dependency injection mechanism?
Are you just trying to avoid using Spring or do you just not like
@SpringBean and the underlying Wicket proxying beneat h the covers?
FYI,
it
has worked fine for us.

You may end up with a solution that is quite convoluted, hard to
learn/maintain, less elegant and hard to get just right in all cases
(for
example testing, serialization/deserialisation etc...). But at the end
of
the day, one of the key features of a framework like Wicket is that
you
 can
do anything that Java lets you - so the choice is always yours.

Regards - Cemal
http://www.jWeekend.co.uk http://jWeekend.co.uk




Sasha Ovsankin wrote:
 > Are you planning on serialising your DAOs?

No -- I mark them as "transient".

 > How will you mock out your "Locator" for unit tests?

I didn't provide the implementation in the parent, but it's pretty
obvious:

      /** Use for unit tests */
      public static class MockLocator extends Locator {
         HashMap<String, Object> map= new HashMap<String, Object>();

         Object find(String name) {
            return map.get(name);
         }

         public void put(String name, Object value) {
            map.put(name, value);
         }
      }

       class MyTest extends TestCase {
         void setUp() {
            MockLocator mockLocator= new MockLocator();
            MyDAO dao= new MyDAO(...);
            mockLocator.put("dao", dao);
            Locator.register(mockLocator);
         }
      }

Hope this makes sense.

jWeekend wrote:
Are you planning on serialising your DAOs?
How will you mock out your "Locator" for unit tests?

Regards - Cemal
http://www.jWeekend.co.uk http://jWeekend.co.uk


Sasha O-2 wrote:
Dear All --

I was having an issue with @SpringBean injection -- my dao class
was
not initialized properly with the dependent beans. I spent some
time
exploring internals of CGLib and Spring Injections and then a
thought struck
me: how really helpful is this injection?

Consider this code:

      class MyPage extends Page {
         ...
         @SpringBean
         MyDAO dao;
         ...
      }

vs. this code:

      class MyPage {
         ...
         MyDAO dao= Locator.find("myDAO", MyDAO.class);
         ...
      }

The Locator is a  pretty straightforward guy who pulls
ApplicationContext out of thin air^^^^^ThreadLocal variable and
looks up on
it, see the example code below.

The former uses annotations, CGLIB and delicate injection. The
latter
uses nothing and is a lot simpler and robust. Aside from marginal
savings in
typing I couldn't find any advantages of the former approach. Can
you?

Unless convinced otherwise, I am going to skip the @SpringBean
altogether and use the Locator thing in my application.

Thanks,
-- Sasha


-----------------------------------------------------------------------
public abstract class Locator {

      abstract Object find(String name);

      static Locator locator= null;

      public static Locator register(Locator inLocator) {
              Locator result= locator;
              locator= inLocator;
              return result;
      }

      public static class SpringLocator extends Locator {
              ApplicationContext context=
WebApplicationContextUtils.getRequiredWebApplicationContext(

 WebApplication.get().getServletContext());
              Object find(String name) {
                      return context.getBean(name);
              }
      }

      /** To be called in the application initialization */
      public static void registerSpringLocator() {
              register(new SpringLocator());
      }

      /** Use for unit tests */
      public static class MockLocator extends Locator {
              @Override
              Object find(String name) {
                      // TODO implement
                      return null;
              }
      }

      public static<T> T find(String name, Class<T> clazz) {
              Object found= locator.find(name);
              if (found==null)
                      return null;
              return clazz.cast(found);
      }
}

-----------------------------------------------------------------------



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to