I'm getting an error when trying to run a Spring application where I am trying to inject dependencies from an application.properties file. Thus, Spring cannot create the bean.
This is the bean that cannot be created without the dependencies:
#Configuration
public class ClientConfig {
private String url;
private String id;
private String secret;
private String scope;
private String tenantId;
private String siteId;
private String listId;
#Autowired
public ClientConfig(
#Value("${client.url}") String url,
#Value("${client.id}")String id,
#Value("${client.secret}") String secret,
#Value("${client.scope}") String scope,
#Value("${client.tenantId}") String tenantId,
#Value("${client.siteId}") String siteId,
#Value("${client.listId}") String listId) {
this.url = url;
this.id = id;
this.secret = secret;
this.scope = scope;
this.tenantId = tenantId;
this.siteId = siteId;
this.listId = listId;
}
public ClientConfig() {
}
public String getUrl() {
return url;
}
public String getId() {
return id;
}
public String getSecret() {
return secret;
}
public String getScope() {
return scope;
}
public String getTenantId() {
return tenantId;
}
public String getSiteId() {
return siteId;
}
public String getListId() {
return listId;
}
}
These are the values in the application.properties file located in src/main/resources:
client:
url: https://google.com
id: ${CLIENT_ID}
secret: ${CLIENT_SECRET}
scope: https://scope.url.com
tenantId: 000-000-000
siteId: "google.com/site/mysite"
listId: "my-list"
The id and secret come from the environment.
I have tried a few different things. I have tried to use the #PropertySource annotation with the classpath:application.properties, but I get an error that the file doesn't exist. I tried moving those #Value tags outside the constructor. I have also tried to hard-code the values within the ClientConfig class. When I did that, I got an error that looked like this:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.demo.graph.GraphConfig required a bean of type 'java.lang.String' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
I'm new to Spring, but based on the training I have done, it seems like if the dependencies are hard-coded right within the class the application context would definitely be able to inject them. I know hard-coding them is not the answer so I'm not even worried about the second error.
Your file is named application.properties but its content you showed is in .yml-format.
In .properties-format your configuration would look like this:
client.url=https://google.com
client.id=${CLIENT_ID}
client.secret=${CLIENT_SECRET}
client.scope=https://scope.url.com
client.tenantId=000-000-000
client.siteId=google.com/site/mysite
client.listId=my-list
Alternatively you could use an application.yml file instead as described here: https://www.baeldung.com/spring-boot-yaml-vs-properties
Related
I have a class in which i want only one property to be injected from the properties file.
The class is like this:
#Getter
public class BatchContext {
private final String city;
private final String channel;
#Value("${table.url: https://www.someurl.com}")
private final String url;
#Builder
public BatchContext(String city, String channel, #Value("${table.url:https://www.someurl.com}") String url) {
this.city = city;
this.channel = channel;
this.url = url;
}
}
I wanted to just pass country and segment to the BatchContext and wanted to load url from the properties file but the url turns out to be null, whats the best way to achieve this.
Madu, it seems your problem is related just to your class.
It is not a Bean for Spring context, then your #Value cannot be injected by Spring.
Try setting your class as an object managed by Spring, e.g. #Component:
#Component
public class BatchContext {...
}
I am currently studying an online Spring Boot course working with Spring Data JPA.
My project includes 2 entities: BDProject and BDUser which have a many to one relationship. When attempting to find projects from user id the following exception is displayed.
EXCEPTION
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'BDProjectController': Unsatisfied dependency expressed through field 'bdProjectService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'BDProjectService': Unsatisfied dependency expressed through field 'bdProjectRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'BDProjectRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.project.bdproject.BDProjectRepository.findByUserID(java.lang.String)! No property userID found for type BDProject!
I have spent hours trying to figure out what's causing this exception, but nothing seems to be fixing it.
MY CODE:
Entities
#Entity
public class BDUser {
#Id
private String userID;
private String bdUsername;
private String bdUserEmail;
private String bdUserPassword;
public BDUser(){
}
public BDUser(String userID, String bdUsername, String bdUserEmail, String bdUserPassword) {
super();
this.userID = userID;
this.bdUsername = bdUsername;
this.bdUserEmail = bdUserEmail;
this.bdUserPassword = bdUserPassword;
}
// getters and setters...
#Entity
public class BDProject {
#Id
private String proID;
private String proName;
private String proCodeOwner;
private String proIDs;
#ManyToOne
private BDUser bdUser;
public BDProject() {
}
public BDProject(String proID, String proName, String proCodeOwner, String proIDs, String userID) {
super();
this.proID = proID;
this.proName = proName;
this.proCodeOwner = proCodeOwner;
this.proIDs = proIDs;
this.bdUser = new BDUser(userID, "", "", "");
}
// getters and setters...
Controller
#RestController
public class BDProjectController {
#Autowired
private BDProjectService bdProjectService;
#RequestMapping("/bdusers/{userID}/bdprojects")
public List<BDProject> getAllProjects(#PathVariable String proID){
return bdProjectService.getAllProjects(proID);
}
#RequestMapping("/bdusers/{userID}/bdprojects/{proID}")
public BDProject getProject(#PathVariable String proID){
return bdProjectService.getProject(proID);
}
#RequestMapping(method= RequestMethod.POST, value="/bdusers/{userID}/bdprojects")
public void addProject(#RequestBody BDProject bdProject, #PathVariable String userID){
bdProject.setBdUser(new BDUser(userID, "", "", ""));
bdProjectService.addProject(bdProject);
}
#RequestMapping(method= RequestMethod.PUT, value="/bdusers/{userID}/bdprojects/{proID}")
public void updateProject(#RequestBody BDProject bdProject, #PathVariable String userID, #PathVariable String proID){
bdProject.setBdUser(new BDUser(userID, "", "", ""));
bdProjectService.updateProject(bdProject);
}
#RequestMapping(method= RequestMethod.DELETE, value="/bdusers/{userID}/bdprojects/{proID}")
public void deleteProject(#PathVariable String proID){
bdProjectService.deleteProject(proID);
}
}
Service
#Service
public class BDProjectService {
#Autowired
private BDProjectRepository bdProjectRepository;
public List<BDProject> getAllProjects(String userID){
List<BDProject> bdProjects = new ArrayList<>();
bdProjectRepository.findByUserID(userID).forEach(bdProjects::add);
return bdProjects;
}
public BDProject getProject(String proID){
return bdProjectRepository.findById(proID).orElse(null);
}
public void addProject(BDProject BDProject){
bdProjectRepository.save(BDProject);
}
public void updateProject(BDProject BDProject){
bdProjectRepository.save(BDProject);
}
public void deleteProject(String proID){
bdProjectRepository.deleteById(proID);
}
}
Repository
public interface BDProjectRepository extends CrudRepository<BDProject, String>{
public List<BDProject> findByUserID(String userID);
}
Any and all help is much appreciated. Thanks!
In BDProject you have property
private BDUser bdUser;
and in the repository you have:
public List<BDProject> findByUserID(String userID);
Error states that in BDProject you don't have property userID which is correct since you have bdUser.
Therefore, please change
findByUserID(String userID) to findByBdUserUserID(String userID)
You have created a BDProjectRepository interface for BDProject entity.
Please modify the method in that repository:
now: public List<BDProject> findByUserID(String userID);
should be: public List<BDProject> findByProID(String proID);
If you want to get BDProject for a specific user you can retrieve it by querying the related object as
public List<BDProject> findByBdUser_UserID(String proID);
When querying by fields in referenced object you should write it like ChildObject_ChildID
public interface BDProjectRepository extends CrudRepository<BDProject, String>
{
public List<BDProject> findByBdUser_UserID(String userID);
}
I have a small class in my Spring-Boot project in which I am getting the some values from the application.properties file. My class is in src/main/java/com/company/package folder and my application properties file in src/main/resources/application.properties. This is my class:
#Component
#Configuration
#PropertySource("classpath:application.properties")
public class ElasticConnection {
private static final String INDEX = "index_name";
public static final String TYPE = "type";
private String user;
private String password;
public ElasticConnection(#Value("${elasticsearch.user}") String user,
#Value("${elasticsearch.password}") String password){
this.user = user;
this.password = password;
}
I am Autowiring this class to the Application class:
#Configuration
#SpringBootApplication
public class ElasticApplication {
#Autowired
ElasticConnection elastic;
public static void main(String[] args) {
SpringApplication.run(ElasticApplication.class, args);
}
}
Now as soon as the constrctor of the ElasticConnection class is called user and password are set to null. I know the values are read properly because InteliJ is kind enough to show the value (until you click on #Value and shows the "${elasticsearch.user}" again)
EDIT: this is the application properties file.
# App config
server.port=8070
# Local ElasticSearch instance configuration
elasticsearch.clustername = elasticsearch
elasticsearch.host = localhost
elasticsearch.port = 9300
#spring.main.allow-bean-definition-overriding=true
# Elasticsearch Settings
elasticsearch.user=test
elasticsearch.password=test
If we want to use the #Value annotation for a constructor argument we must not forget to add the #Autowired annotation on the constructor as well.So your code should be :
#Component
#PropertySource("classpath:application.properties")
public class ElasticConnection {
private static final String INDEX = "index_name";
public static final String TYPE = "type";
private String user;
private String password;
#Autowired
public ElasticConnection(#Value("${elasticsearch.user}") String user,
#Value("${elasticsearch.password}") String password){
this.user = user;
this.password = password;
}
This enables spring to use constructor injection for your fields.
Instead of injecting the values via the constructor you can also try the following in your code :
#Component
#PropertySource("classpath:application.properties")
public class ElasticConnection {
private static final String INDEX = "index_name";
public static final String TYPE = "type";
#Value("${elasticsearch.user}")
private String user;
#Value("${elasticsearch.password}")
private String password;
//setters and getters
}
Or you can even use #ConfigurationProperties annotation to read values from the property files.
Related : Spring #Autowire on Properties vs Constructor
#Component
public class Bot extends TelegramLongPollingBot {
#Value("${camel.component.telegram.authorization-token}") //properties
private String botToken; //null
TelegramBot bot = TelegramBotAdapter.buildDebug(botToken);
.
.
.
}
I don't understand why is not injected a param value defined in properties.
Notice that #Value do not support relaxed binding, so check your property.
#Component
#PropertySource("file:${app_env_path}/${app_env}_DBconnection.properties")
public class DBProperties {
#Value("${driver.class.name}")
private String driverClassName;
#Value("${db.url}")
private String url;
#Value("${db.username}")
private String username;
#Value("${db.password}")
private String password;
#Value("${db.poolsize}")
private String poolsize;
//setters and getters
}
Property file -
driver.class.name=oracle.jdbc.OracleDriver
db.url=
db.username=
db.password=
db.poolsize=100
app_env_path = path where the location of the file
app_env = SIT/PROD
I was trying to use Spring Data JPA on Spring Boot and I kept getting error, I can't figure out what the problem is:
Unable to locate Attribute with the the given name [firstName] on
this ManagedType [com.example.h2demo.domain.Subscriber]
FirstName is declared in my entity class. I have used a service class with DAO before with different project and worked perfectly.
My Entity class (getters and setters are also in the class) :
#Entity
public class Subscriber {
#Id #GeneratedValue
private long id;
private String FirstName,LastName,Email;
public Subscriber(long id, String firstName, String lastName, String email) {
this.id = id;
this.FirstName = firstName;
this.LastName = lastName;
this.Email = email;
}
}
...
My Repository Class
#Component
public interface SubscriberRepository extends JpaRepository<Subscriber,Long> {
Subscriber findByFirstName(String FirstName);
Subscriber deleteAllByFirstName(String FirstName);
}
My Service Class
#Service
public class SubscriberService {
#Autowired
private SubscriberRepository subscriberRepository;
public Subscriber findByFirstName(String name){
return subscriberRepository.findByFirstName(name);
}
public Subscriber deleteAllByFirstName(String name){
return subscriberRepository.deleteAllByFirstName(name);
}
public void addSubscriber(Subscriber student) {
subscriberRepository.save(student);
}
}
And My Controller class:
#RestController
#RequestMapping("/subscribers")
public class SubscriberController {
#Autowired
private SubscriberService subscriberService;
#GetMapping(value = "/{name}")
public Subscriber findByFirstName(#PathVariable("name") String fname){
return subscriberService.findByFirstName(fname);
}
#PostMapping( value = "/add")
public String insertStudent(#RequestBody final Subscriber subscriber){
subscriberService.addSubscriber(subscriber);
return "Done";
}
}
Try changing private String FirstName,LastName,Email; to private String firstName,lastName,email;
It should work.
findByFirstName in SubscriberRepository tries to find a field firstName by convention which is not there.
Further reference on how properties inside the entities are traversed https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-property-expressions
The same problem was when i had deal with Spring Data Specifications (https://www.baeldung.com/rest-api-search-language-spring-data-specifications)
Initial piece of code was:
private Specification<Project> checkCriteriaByProjectNumberLike(projectNumber: String) {
(root, query, criteriaBuilder) -> criteriaBuilder.like(root.get("project_number"), "%" + projectNumber)
}
The problem was in root.get("project_number"). Inside the method, I had to put the field name as in the model (projectNumber), but I sent the field name as in the database (project_number).
That is, the final correct decision was:
private Specification<Project> checkCriteriaByProjectNumberLike(projectNumber: String) {
(root, query, criteriaBuilder) -> criteriaBuilder.like(root.get("projectNumber"), "%" + projectNumber)
}
After I change my entity class variables from capital letter to small letter for instance Username to username the method Users findByUsername(String username); is working for me now .
As per specification , the property names should start with small case.
...The resolution algorithm starts with interpreting the entire part (AddressZipCode) as the property and checks the domain class for a property with that name (uncapitalized)....
It will try to find a property with uncapitalized name. So use firstName instead of FristName and etc..