Announcement Announcement Module
Collapse
No announcement yet.
Autowiring and constructor injection Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Autowiring and constructor injection

    I am trying to autowire a bean from the following context:

    Code:
    <!-- AutowireTest2.xml -->
    <bean id="stringProperty" class="java.lang.String">
      <constructor-arg value="Hello from String"/>
    </bean>
    <bean id="beanProperty" class="MyBean">
      <property name="stringProperty" value="Hello from MyBean"/>
    </bean>
    It seens that 'stringProperty' using constructor injection is not properly wired.
    The other property is ok.

    ---
    Here, in essence, is my setup:
    ---

    Code:
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
    
    public class AutowireTest2
    {
        private String stringProperty;
        public String getStringProperty() {
            return stringProperty;
        }
        public void setStringProperty( String stringProperty ) {
            this.stringProperty = stringProperty;
        }
    
        private MyBean beanProperty;
        public MyBean getBeanProperty() {
            return beanProperty;
        }
        public void setBeanProperty( MyBean beanProperty ) {
            this.beanProperty = beanProperty;
        }
    
        public static void main( String[] args ) 
        {
            ApplicationContext ctx = 
                new ClassPathXmlApplicationContext( "AutowireTest2.xml" );
    
            AutowireTest2 app = new AutowireTest2();
            int autowireMode = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
            boolean dependencyCheck = false;
            
            // Autowire by name
            ctx.getAutowireCapableBeanFactory().
                autowireBeanProperties(app, autowireMode, dependencyCheck);
    
            System.out.println( ctx.getBean( "stringProperty" ) );
            System.out.println( app.getStringProperty() );
            System.out.println( app.getBeanProperty().getStringProperty() );
        }
    }
    Code:
    public class MyBean 
    {
    	private String stringProperty;
    	public String getStringProperty() {
    		return stringProperty;
    	}
    	public void setStringProperty( String stringProperty ) {
    		this.stringProperty = stringProperty;
    	}
    }
    The output is:
    Hello from String
    null
    Hello from MyBean

    Instead of the null output, should it not say 'Hello from String' ?
    Behavior is the same no matter whether I try autowiring by name or by type.
    Can anyone help?
    Thanks,
    Hubert
    Last edited by Hubert Kauker; Aug 8th, 2007, 09:32 AM.

  • #2
    Yep...don't use autowiring. Really. I know that sounds harsh, and I could provide the answer, but do you really need to use it?

    Also, please put code/xml listings in code tags.

    Comment


    • #3
      The reason I'm using autowire is that I'm trying to integrate Spring with a third party commercial framework which insists on creating its own objects (and has no built-in Spring support ).
      And I have no access to the source code, naturally.

      Sorry about not using code tags. Didn't know about them.
      Hubert

      Comment


      • #4
        Ah OK, I see.

        Not knowing anything about your situation this might not work, but I would rather create individual FactoryBeans that take care of constructing, and then autowiring the third party classes...would that work?

        If there only one or two third party classes that I need, I would go down that route.

        If you insist on sticking with autowiring, there are three different types of autowiring ... bad, dangerous and terrible. No seriously, if you do want to go down that route please read http://static.springframework.org/sp...ctory-autowire.

        Can you edit your existing post and wrap the code listings in the code tag please.

        Comment


        • #5
          I don't think autowiring is what you need. Autowiring (by itself) allows you to magically inject stuff into _Spring_ created beans. AspectJ injection-on-the-fly support will allow you to prototype externally created objects, with or without autowiring. Take a look at 6.8.1. "Using AspectJ to dependency inject domain objects with Spring".

          Comment


          • #6
            Thanks for the hint about editing.

            Now, my third party framework is similar to Struts in that it makes me extend from a given base class, called 'Adapter' in this case.
            In order to get instances of my class created, I need to give the classname as a string.
            The framework insists on creating the instance itself, and I do not see how I can get in my own FactoryBean.
            When an instance has been created and all framework specific initializations have been performed, the lifecycle method 'init' is automatically called by the framework.
            It is my idea to override 'init' by my own method like this:

            Code:
            public class MyAdapter extends Adapter
            {
                // M y   o w n   p r o p e r t i e s
                private MyType myObj;
                public MyType getMyType() {
                    return myObj;
                }
                public void setMyType( MyType myObj ) {
                    this.myObj = myObj;
                }
            
                // More ...
            
                // L i f e c y c l e   m e t h o d 
                public void init()
                {
                    ServletContext servletContext =
                        findHttpServletRequest().getSession().getServletContext();
            
                    applicationContext =
                        WebApplicationContextUtils.
                            getWebApplicationContext( servletContext );
            
                    int autowireMode = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
                    boolean dependencyCheck = false;
            
                    // A u t o w i r e    	
                    getApplicationContext().getAutowireCapableBeanFactory().
                        autowireBeanProperties( this, autowireMode, dependencyCheck );
                }
            }
            Well, of course, I would not put that method into *every* class of mine, but I would extend from my own base class which was extended from Adapter, in turn. Anyway.

            I would then like to have bean definitions of the following kind in the application context to get my adapter fully wired:

            Code:
            <bean id="myType" class="MyTypeImpl">
                <!-- constructor args or properties ... -->
            </bean>
            But the doc page you directed me to clearly says: "it is currently not possible to autowire so-called "simple" properties such as primitives, Strings, and Classes (and arrays of such simple properties)".

            Well that's the reason, indeed.
            Or is it?
            The doc says, that is by-design and should be condered a feature.
            I wonder why.
            I tried with my own class 'MyString' wrapping the String class, and everything went fine, indeed.

            Maybe that's the way, how I shall do it.
            Or would you recommend another approach, still?
            Hubert
            Last edited by Hubert Kauker; Aug 8th, 2007, 10:50 AM.

            Comment


            • #7
              Thanks for the hint at 6.8.1.
              AspectJ certainly is a candiate. However, to quote from the doc:

              "Integration code for other frameworks can leverage this interface to wire and populate existing bean instances that Spring does not control the lifecycle of. This is particularly useful for WebWork Actions and Tapestry Page objects, for example."

              See: org.springframework.beans.factory.config.AutowireC apableBeanFactory

              Comment


              • #8
                I am not sure how you get hold of the framework style classes, if that has it's own lifecycle then yes, you must hook into that. I mention factoryBeans because if I have a 3rd party framework X which provides a bean XServer then I would create an XServerFactoryBean. My classes which require an XServerFactoryBean would be dependency injected with it via the factory bean.

                Assume the XService requires a datasource thenthe code would look something like:

                Code:
                public class XServiceFactoryBean implements FactoryBean {
                  private DataSource dataSource;
                
                  // getters/setters/constructors ignored
                
                  public Object getObject() {
                      XService service = Framework.create("com.yourframework.XService");
                      service.setDataSource(dataSource);
                      return service;
                  }
                }
                then in XML:

                Code:
                  <bean id="XService" class="my.XServiceFactoryBean">
                    <constructor-arg ref="dataSource"/>
                  </bean>
                
                  <bean id="beanThatNeedsAnXService" class="...">
                    <property name="xService" ref="xService"/>
                  </bean>
                this approach works really well if your code needs access to 3rd party code
                . If OTOH the 3rd party needs access to your code, then it is a bit more complicated. If you know in advance the dependencies the 3rd party code needs, then you still don't need to use autowiring, just do it by hand.

                Alternatively, (as dejanp) mentioned, you could use part of the Aspect integration and have Spring intercept the construction of the object and do the DI then, but if you can keep is simple with factory beans....

                Comment


                • #9
                  Your pattern will not work here.
                  My third party framework X only knows its adapters (and other classes), but totally ignores my own application context.
                  And it is not Spring aware.

                  Therefore, a bean definition for 'beanThatNeedsAnXService' is useless.
                  It would never be referenced.

                  As I said, it is all very similar to Struts.
                  X creates adapters which I need to provide extended from 'Adapter'.
                  X creates instances of my classes, whenever X thinks fit.
                  X does *not* pull them from my web application context.
                  The only thing which is guaranteed, and where I can get my foot in, is that the 'init' method is called at some appropriate moment.

                  Any time later, X will call other methods of my adapter, of course, like 'doProcess' or whatever, but they do not concern us here.
                  But when those calls come, I would like to have a fully wired adapter. See?

                  Unfortunately, the Spring integration to Struts cannot be carried over, since X does not load plugins like Struts does, so that I cannot get X to use a DelegatingRequestProcessor or a DelegatingAdapterProxy or whatever.

                  Comment


                  • #10
                    I see. Yes, you did actually make that clear in your earlier post. Shame as it is a much nicer pattern

                    The only advice I can offer really (although I am sure there is a more elegant solution) is to do dependency lookup in each class, so each class is responsible for doing it themselves:

                    Code:
                      class SpringIntegrationFrameworkClass extends FrameworkClass {
                          public void init() { 
                               ApplicationContext ctx = getAppContextSomehow();
                               doWithBeanFactory(ctx);
                          }
                    
                          public void doWithBeanFactory(BeanFactory factory) {
                          }
                      }
                    
                      MyClass extends SpringIntegrationFrameworkClass {
                          private Service service;
                    
                          public void doWithBeanFactory(BeanFactory beanFactory) {
                              service = (Service) beanFactory.get("service");
                          }
                      }
                    would work if you only have a small number of framework specific classes, otherwise....no idea.


                    Actually, one thing might work quite well....could you implement your own delegating pattern?

                    Can you not have a single implementation which does nothing more than delegate to a spring managed bean? Each framework specific class basically provides the spring bean name...very similiar to DelegatingFilterProxy?

                    Comment


                    • #11
                      Don't worry. Yes, that pattern is nicer, and I have already approached the vendor of my third party framework to support it.

                      However, I have found another workaround, which will do for me at the moment.
                      I was curious to see what those "design-decisions" might be which are alluded to in 3.3.6 of the user manual.
                      So I looked up the source of method autowireBeanProperties in AbstractAutowireCapableBeanFactory in package org.springframework.beans.factory.support.
                      It calls populateBean, which calls autowireByName which calls unsatisfiedNonSimpleProperties, all from the same class, which finally calls BeanUtils.isSimpleProperty.
                      Now, it is exactly the latter call which is doing all the "damage".

                      So I will probably implement some doWithBeanFactory method, as you suggested, and assemble those few source lines I found above without that ominous call to isSimpleProperty.

                      Another workaround would be to use StringBuffer instead of String, because that is not a type which is rejected by isSimpleProperty, and it is just as easy to configure as String in those rare cases I need it.

                      By the way, I would like to observe that I named this thread inappropriately: it has nothing to do with constructor injection as such. It should rather be called "Autowiring of String and other simple properties".

                      To complete the picture: did you observe that the JavaDoc of autowireBeanProperties does not mention with a single word, that String and other simple properties are not autowired? That piece of information is only given in 3.3.6 of the manual.
                      I feel, that is something to be repaired. Better still, the restriction should be abandoned altogether, or some sound reason should be made public.
                      I guess you have access to an active committer to that package and can draw his attention to this issue.

                      Thanks a lot for your help.
                      Hubert

                      Comment

                      Working...
                      X