Announcement Announcement Module
Collapse
No announcement yet.
IoC with multiple arguments Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • IoC with multiple arguments

    Hi,

    assume the following class:

    package simple.test;

    public class TestClass
    {
    private int x;
    private int y;
    private int width;
    private int height;

    public void setBounds(int x,int y,int width,int height)
    {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    }
    };

    Is this possible to inject from spring, and how do the spring context look like?
    It has support for map's, sets, lists and so on, even multiple args in the constructor injection. Have not found any documentation for doing this ?

    Anyone ?

    Cheers,
    Fredrik

  • #2
    Spring relies on standard JavaBeans handling for assigning property values. Therefore your case will not be supported out-of-the-box.

    Maybe you can use some more sophisticated mechanisms like BeanPostProcessors or FactoryBeans to achieve initializations like this.

    Regards,
    Andreas

    Comment


    • #3
      You *can* pass them in via constructor args, so if you had:

      Code:
        public class TestClass {
          final int x;
          final int y;
          final int width;
          final int height;
      
          public TestClass(final int x, final int y, final int width, final int height) {
            this.x = x;
            this.y = y; 
            etc.
          }
        }
      in your context you would do:

      Code:
        <bean id="yourTestCase" class="TestCase">
          <constructor-arg index="0" value="189"/>
          etc.
        </bean>
      Although, thinking about it, not sure bean autowiring works with primitives

      Comment


      • #4
        Originally posted by yatesco
        You *can* pass them in via constructor args, so if you had:
        That is indeed possible. But you have this option only if you are able to provide such a constructor (i.e. it is no third-party class).

        Originally posted by yatesco
        Although, thinking about it, not sure bean autowiring works with primitives
        As far as I know primitives should pose no problem for spring configuration.

        Regards,
        Andreas

        Comment


        • #5
          Hi again,

          The example i quoted was originally
          from java.awt.Button (extended from java.awt.Component),
          and the method

          void setBounds(int x, int y, int width, int height)

          and that's why it makes it harder for me to gets IoC working with this
          components

          Or actually not that big problem since it also
          has the setter...

          void setBounds(Rectangle r)

          so the xml to do this then get's a bit bigger but still feasible,
          and this aligns well with the bean standard, but gives more
          declarations in the xml..

          Code:
          <bean id="myButton" class="java.awt.Button">
              <property name="bounds" ref="rectangle"/>
              <property name="label" value="Click me..."/>
          </bean>
          
          <bean id="rectangle" class="java.awt.Rectangle">
              <constructor-arg value="0"/>
              <constructor-arg value="0"/>
              <constructor-arg value="100"/>
              <constructor-arg value="10"/>
          </bean>
          I suppose i also could do the declaration programatically.

          Thanx guys =)

          Cheers,
          Fredrik

          Comment


          • #6
            If you are only using that rectangle in myButton then:

            Code:
            <bean id="myButton" class="java.awt.Button">
                <property name="bounds">
                    <bean class="java.awt.Rectangle">
                       <constructor-arg value="0"/>
                       <constructor-arg value="0"/>
                       <constructor-arg value="100"/>
                       <constructor-arg value="10"/>
                   </bean> 
                </property>
                <property name="label" value="Click me..."/>
            </bean>

            Comment


            • #7
              I have the exact same problem.
              This post is a bit old now.

              Does the current version of the framework allow this?
              Unfortunately there is nothing I can do. I am using a Java class which has a parameterless constructor. I have to use setters that take more then one argument.

              So I am at a dilemma.

              Any help or advice would be much appreciated.
              Last edited by polski; May 29th, 2009, 08:22 AM.

              Comment


              • #8
                Using @Autowired and @Resource

                It is possible to inject instance variables into a test class, but you do have a chicken and egg problem. JUnit (or TestNG) will instantiate the test class instance, so Spring doesn't instantiate it. The Spring TestContext classes and annotations will help, though, but I haven't been able to use define the test instance as a bean in the context file. Instead, I do this:

                Code:
                // In NameValidatorTest.java
                @RunWith(SpringJUnit4ClassRunner)
                @ContextConfiguration
                public class NameValidatorTest {
                    @Autowired
                    private NameValidator validator;
                }
                and
                Code:
                <!-- In NameValidatorTest-context.xml -->
                <bean id="nameValidator" class="com.erjablow.NameValidator"/>
                <!-- Or use component scan, etc. -->
                If I want to create a sample Name instance, I can do that inline in the Java file. If I want to define test data in the context file, I have to use dependency lookup:
                Code:
                @ContextConfiguration
                public class NameValidatorTest implements ApplicationContextAware {
                    private ApplicationContext applicationContext;
                    private Name name;
                    @Autowired
                    private NameValidator validator;
                    public setApplicationContext(ApplicationContext applicationContext) {
                        this.applicationContext = applicationContext;
                    }
                    @Before
                    public void initName() {
                        name = (Name) applicationContext.getBean("name");
                    }
                }
                and
                Code:
                <!-- In NameValidatorTest-context.xml -->
                <bean id="nameValidator" class="com.erjablow.NameValidator"/>
                <!-- Or use component scan, etc. -->
                <bean id="name" class="com.erjablow.Name" scope="prototype"
                    p:givenName="Ming"
                    p:middleName="the"
                    p:surName="Merciless"/>
                Normally I wouldn't use the p namespace, but I'm willing to do that in test code.

                For items that remain constant, you can use @Resource instead of dependency lookup.
                Code:
                <bean id="button1" class="java.awt.Button">
                    <property name="bounds" ref="rectangle1"/>
                    <property name="label" value="Click me..."/>
                </bean>
                
                <bean id="rectangle1" class="java.awt.Rectangle">
                    <constructor-arg value="0"/>
                    <constructor-arg value="0"/>
                    <constructor-arg value="100"/>
                    <constructor-arg value="10"/>
                </bean>
                <bean id="button2" class="java.awt.Button">
                    <property name="bounds" ref="rectangle2"/>
                    <property name="label" value="Click me..."/>
                </bean>
                
                <bean id="rectangle2" class="java.awt.Rectangle">
                    <constructor-arg value="200"/>
                    <constructor-arg value="200"/>
                    <constructor-arg value="100"/>
                    <constructor-arg value="10"/>
                </bean>
                and
                Code:
                @Resource
                private Button button1;
                @Resource
                private Button button2;
                Last edited by erjablow; May 29th, 2009, 11:01 AM. Reason: Forgot a prototype scope.

                Comment


                • #9
                  I solved this but the solution is cumbersome.
                  Not really Java+Spring 2.0 (as appose to Web 2.0).

                  I want to do the following:

                  Code:
                  SomeClass someobject = new SomeClass();
                  someobject.set("String1","String2");
                  This is not possible by the properties xml tags or bean method-factory.
                  Becuase:
                  * No more then one argument can be passed to the properties
                  * The set method is a void method (method-factory wants a return type)

                  So the way I solved this was to use the "MethodInvokingFactoryBean" class:
                  Code:
                   <bean id="someobject" class="SomeClass" />
                  
                   <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
                   <property name="targetObject"><ref local="someobject"/></property>
                   <property name="targetMethod"><value>set</value></property>
                   <property name="arguments"> 
                     <list>
                        <value> "String1" </value>
                        <value> "String2" </value>
                     </list>
                   </property>
                  </bean>
                  Not the most elegant solution. It's almost like programming java, but it works.

                  Let me know if there is any neater way or how to clean up and compact the code above.

                  Regards,
                  polski

                  Comment

                  Working...
                  X