Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with dependency injection [SPR-17602] #22134

Open
spring-issuemaster opened this issue Dec 14, 2018 · 1 comment

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Dec 14, 2018

Zohar Cohen opened SPR-17602 and commented

Hi,

I am facing a strange behavior with dependency injection in my project, there is an unexpected initialization of one of our constructors.

I am using Spring 5.0.6.RELEASE with XML configuration, we have the following structure:

Entity P - this class depended on two entities and a String:

public class P {public class P {

  public P(D1 d1, D2 d2, String input){ 
     System.out.println("P Constructor: D1: "+d1+", D2: "+d2+" , Input: "+input);
  }
}

 Entity S - this class inject to the depended class, the class contains two constructors, we are                     initializing only the empty constructor

 

public class S {public class S {

 public S() {
   System.out.println("S Empty Constructor!");
 }

 public S(String str) {
   System.out.println("S Argument Constructor!");
 }
}

 

 Entity D1

public class D1 {public class D1 {

 public D1(String input) {
   System.out.println("D1 Constructor with input: " + input);
 }

 public D1(S s, String input) {
   System.out.println("D1 Constructor with two inputs");
 }
}

 

Entity D2

 

public class D2 {public class D2 {

  public D2(String input) {
     System.out.println("D2 Constructor with input: " + input);
 }

 public D2(S s, String input) {
    System.out.println("D2 Constructor with two inputs");
 }
}

 

XML configuration:

<beans xmlns:context="http://www.springframework.org/schema/context"<beans xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="        http://www.springframework.org/schema/beans             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd        http://www.springframework.org/schema/context         http://www.springframework.org/schema/context/spring-context-3.0.xsd        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">

 <bean id="p" class="com.zohar.P"> 
    <constructor-arg ref="d1" /> 
    <constructor-arg ref="d2" /> 
    <constructor-arg value="MS" /> 
</bean>

 <bean id="d1" class="com.zohar.D1">
      <constructor-arg value="MS" />
 </bean> 

<bean id="d2" class="com.zohar.D2">
  <constructor-arg  value="MS" /> 
</bean>
 <bean id="s" class="com.zohar.S" />

</beans>

 

 Based on the configuration file, the following activities should happen:

  1. S - calling to empty constructor.

  2. P - we are calling to the contractors with two depended and MS string.

  3. D2 - constructorr with one input 'MS'.

  4. D1 - constructore with input 'MS'

 

The issue is that during the autowiring process Spring initializes the S constructor with the String argument which is not expected to be called.
Program Output:
S Argument Constructor!
D1 Constructor with input: MS
S Argument Constructor!
D2 Constructor with input: MS
P Constructor: D1: com.zohar.D1@4566e5bd, D2: com.zohar.D2@1ed4004b , Input: MS
S Empty Constructor!
 
This seems like a private case due to the second constructors that the depended class have (Seems like an issue with the reflection process).
  
The solution to this issue is to add the wrapper class as a type to the 'constructor-arg' tag:
 
<bean id="p" class="com.zohar.P">
<constructor-arg ref="d1" />
<constructor-arg ref="d2" />
<constructor-arg  type="java.lang.String"  value="MS" />
</bean>
 
<bean id="d1" class="com.zohar.D1">
<constructor-arg type="java.lang.String"  value="MS" />
</bean>
<bean id="d2" class="com.zohar.D2">
<constructor-arg type="java.lang.String"  value="MS" />
</bean>
 
The question is: why we are having this issue in case the type is not set where it is not mandatory? 
 
Attached is the zip with this example.
 
Thank you very much in advance.
 

Zohar

 

 

 

 

 


Affects: 5.0.6

Attachments:

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Dec 19, 2018

Zhang Jie commented

When you specify bean by

<bean id="d1" class="com.zohar.D1">
      <constructor-arg value="MS" />
 </bean>

Spring doesn't find constructor D1(String input) at first time, it loops all of constructors declared by D1, on my machine, the order is first D1(S s, String input), then D1(String input). When checking D1(S s, String input), S(String str) is involved because of constructor-arg MS, then Spring finally finds that D1(String input) satisfies constructor-arg MS instead of D1(S s, String input), the detail is in ConstructorResolver.java.
Your solution specifies type in constructor-arg, the code goes differently at here, when doesn't specify type in constructor-arg, valueHolder will not be null, while valueHolder will be null when specify type in constructor-arg.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.