Jump to content

Help with spring constructor arguments in injecting dependencies

I have wrote a simple code with a class with a constructor that takes a int value and sets it to the data member and displays it later. i am trying to inject the value through the xml config file while creating the bean. I have attached the config xml and the class below but while running the code it is returning error.

Error:-

 

 

Parameter 0 of constructor in com.helloworld.first.classa required a bean of type 'java.lang.String' that could not be found.


Action:

Consider defining a bean of type 'java.lang.String' in your configuration.

Screenshot from 2024-01-22 23-51-03.png

Screenshot from 2024-01-22 23-51-13.png

Link to comment
Share on other sites

Link to post
Share on other sites

You typically inject services (i.e. other classes), not data. To be able to inject an int, you'd first need something that provides an int to be injected. If you want to inject configuration values, you create a class, annotate it as a configuration class, then add that configuration class to your constructor.

 

(also please… try to keep to Java coding standards. Class names are capitalized, not all lower case and PLEASE Use Code Tags, don't post screenshots of your code)

 

application.yml

appname:
  configuration:
    someValue: 5

 

MyConfigurationProperties.java

@ConfigurationProperties(prefix = "appname.configuration")
public class MyConfigurationProperties {

	private int someValue = 0;
  
	public int getSomeValue() {
		return someValue;
	}

	public void setSomeValue(int someValue) {
		this.someValue = someValue;
	}
}

 

MyService.java

@Service
@EnableConfigurationProperties({ MyConfigurationProperties.class })
public class MyService {

	private MyConfigurationProperties myConfigurationProperties;

	public MyService(MyConfigurationProperties myConfigurationProperties) {
		this.myConfigurationProperties = myConfigurationProperties;
	}
}

 

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

7 hours ago, Eigenvektor said:

You typically inject services (i.e. other classes), not data. To be able to inject an int, you'd first need something that provides an int to be injected. If you want to inject configuration values, you create a class, annotate it as a configuration class, then add that configuration class to your constructor.

 

(also please… try to keep to Java coding standards. Class names are capitalized, not all lower case and PLEASE Use Code Tags, don't post screenshots of your code)

 

application.yml

appname:
  configuration:
    someValue: 5

 

MyConfigurationProperties.java

@ConfigurationProperties(prefix = "appname.configuration")
public class MyConfigurationProperties {

	private int someValue = 0;
  
	public int getSomeValue() {
		return someValue;
	}

	public void setSomeValue(int someValue) {
		this.someValue = someValue;
	}
}

 

MyService.java

@Service
@EnableConfigurationProperties({ MyConfigurationProperties.class })
public class MyService {

	private MyConfigurationProperties myConfigurationProperties;

	public MyService(MyConfigurationProperties myConfigurationProperties) {
		this.myConfigurationProperties = myConfigurationProperties;
	}
}

 

I searched on internet but it seems constructor value injection is possible this seems like a roundabout way of doing the same. 

Link to comment
Share on other sites

Link to post
Share on other sites

8 hours ago, Eigenvektor said:

You typically inject services (i.e. other classes), not data. To be able to inject an int, you'd first need something that provides an int to be injected. If you want to inject configuration values, you create a class, annotate it as a configuration class, then add that configuration class to your constructor.

 

(also please… try to keep to Java coding standards. Class names are capitalized, not all lower case and PLEASE Use Code Tags, don't post screenshots of your code)

 

application.yml

appname:
  configuration:
    someValue: 5

 

MyConfigurationProperties.java

@ConfigurationProperties(prefix = "appname.configuration")
public class MyConfigurationProperties {

	private int someValue = 0;
  
	public int getSomeValue() {
		return someValue;
	}

	public void setSomeValue(int someValue) {
		this.someValue = someValue;
	}
}

 

MyService.java

@Service
@EnableConfigurationProperties({ MyConfigurationProperties.class })
public class MyService {

	private MyConfigurationProperties myConfigurationProperties;

	public MyService(MyConfigurationProperties myConfigurationProperties) {
		this.myConfigurationProperties = myConfigurationProperties;
	}
}

 

I was referring to this documentation  https://www.baeldung.com/constructor-injection-in-spring see point no 4.

Link to comment
Share on other sites

Link to post
Share on other sites

2 hours ago, Souranil21 chakraborty said:

Also did u meant to say application.xml or .yml?

No, I meant to say .yml (Yet Another Markup Language, aka yaml or yml).

 

It's a configuration file that you put in the application's directory. So you can change values without having to recompile. It may be "roundabout", but it's a lot more common than injecting raw values via XML.

 

As I said above, injection is typically used to inject other classes marked with @Component/@Service, it is not generally used to inject raw values.

 

In any case, I think you would need to change your XML configuration like this:

<constructor-arg index="0" type="int" value="12"/>

The one thing you're missing is the index, while the type seems to be optional (i.e. it can typically figure that one out on its own)

 

At second glance, I think it may be trying to use field/property injection rather than constructor injection. It is trying to inject the value into the field "String n". The issue may be caused be fact that the constructor argument is named "n", but is assigned to "a" instead.

 

You should really try to follow proper naming conventions and also make sure your fields and associated getters/setters are named appropriately. A lot of automatic stuff Spring does is based on names.

@Component
public class ClassA implements Base {

    private String n = "…";
    
    private int a;

    public ClassA(int a) {
        this.a = a;
    }

    public void setN(String n) {
        this.n = n;
    }

    public String getN() {
        return n;
    }
}

 

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

17 minutes ago, Eigenvektor said:

No, I meant to say .yml (Yet Another Markup Language, aka yaml or yml).

 

It's a configuration file that you put in the application's directory. So you can change values without having to recompile. It may be "roundabout", but it's a lot more common than injecting raw values via XML.

 

As I said above, injection is typically used to inject other classes marked with @Component/@Service, it is not generally used to inject raw values.

 

In any case, I think you would need to change your XML configuration like this:

<constructor-arg index="0" type="int" value="12"/>

The one thing you're missing is the index, while the type seems to be optional (i.e. it can typically figure that one out on its own)

 

At second glance, I think it may be trying to use field/property injection rather than constructor injection. It is trying to inject the value into the field "String n". The issue may be caused be fact that the constructor argument is named "n", but is assigned to "a" instead.

 

You should really try to follow proper naming conventions and also make sure your fields and associated getters/setters are named appropriately. A lot of automatic stuff Spring does is based on names.

@Component
public class ClassA implements Base {

    private String n = "…";
    
    private int a;

    public ClassA(int a) {
        this.a = a;
    }

    public void setN(String n) {
        this.n = n;
    }

    public String getN() {
        return n;
    }
}

 

i have tried writing my xml file contents like this that you mentioned but it  didn't worked

Link to comment
Share on other sites

Link to post
Share on other sites

2 minutes ago, Souranil21 chakraborty said:

i have tried writing my xml file contents like this that you mentioned but it  didn't worked

Like I said, try fixing the names of your variables so they match. And change your fields to private.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

11 minutes ago, Eigenvektor said:

Like I said, try fixing the names of your variables so they match. And change your fields to private.

I finally managed to solve it.It turns out i need to add a no parameter default constructor in the ClassA and it worked perfectly with dependency injection through consstructor.

<

private String n = "…";
 
private int a;
public ClassA(){}
public ClassA(int a) {
this.a = a;
}
 
public void setA(int n) {
this.a = n;
}
public void display(){
System.out.printf("This is the display function of class a printing this statement.\n");
}
public int getA() {
return a;
}

>

Link to comment
Share on other sites

Link to post
Share on other sites

The reason it failed before is because you had a field named "n" and a constructor argument named "n".

 

From Spring's point of view these belong together. And because the field is package-private, rather than private, Spring tries to inject into the field, rather than going through the constructor.

 

You've essentially worked around the actual issue rather than solving it.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×