I am working on a spring project where I need to read multiple account credentials (login and password) from application yml file.
I have written the credentials as an associative array like this (I don't know any better way to do it):
app:
mail:
accounts:
- login: firstlogin
password: firstpassword
- login: secondlogin
password: secondpassword
Then I mapped these values to spring application with #Value annotation:
#Service
public class MyClass {
#Values("${app.mail.accounts}")
private List<Map<String, String>> accounts;
...
}
But spring keep throwing an Exception because it fails to read these values.
Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException:
Could not resolve placeholder 'intelaw.mail.accounts' in value "${app.mail.accounts}"
Without changing your application.yml, you can tune your datastructures and make this work.
Create a class Account
class Account {
private String login;
private String password;
//constructors, getters and setters here
}
and read it using a class annotated with #ConfigurationProperties
#Component
#ConfigurationProperties("app.mail")
class MyClass {
private List<Account> accounts = new ArrayList<>();
//getters and setters here
}
and in your service class, you can use it like :
#Autowired
private MyClass myClass;
void someMethod() {
myClass.getAccounts();
}
Related
I'm creating dynamic collections by using mongoTemplate in service layer. Upto this everything went well but when saving into collection dynamically makes issue. explaining here...
Service Layer
public void createCollection(String collectionName) {
mongoTemplate.createCollection(collectionName);
}
public Object updateLessonOrSurveyOrQuery(String courseID, int levelNo, CourseAsset courseAssetToUpdate) {
.....
courseAssetRepo.saveByCourseID(courseID, courseAssetToUpdate);
.....
}
Repo Layer
#Repository
public interface CourseAssetRepo extends MongoRepository<CourseAsset, String> {
ArrayList<CourseAsset> findAllByCourseID(String courseID);
void saveByCourseID( String courseID, CourseAsset courseAsset);
}
findAllByCourseID working but saveByCourseID not woking;
POJO class
#Data
public class CourseAsset {
private int level;
private String title;
private String courseID;
}
ERROR :
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'courseAssetRepo' defined in com.dotbw.learn.repo.CourseAssetRepo defined in #EnableMongoRepositories declared on MongoRepositoriesRegistrar.EnableMongoRepositoriesConfiguration: Could not create query for public abstract void com.dotbw.learn.repo.CourseAssetRepo.saveByCourseID(java.lang.String,com.dotbw.learn.model.CourseAsset); Reason: No property 'saveByCourseID' found for type 'CourseAsset'
i can understand repo expects CourseAsset Data inside the pojo class. But while saving how we can provide this value.
i have tried many way as ChatGPT said but nothing worked.
I have properties like this:
credentials:
userid: <userid>
password: <password>
I have a POJO:
#Setter
public class Credentials {
private String userid;
private String password;
However, this POJO is in another jar, so I can't add annotations. So I thought I'd try something like this:
#Configuration
#Getter
#Setter
#ConfigurationProperties("credentials")
public class MyCredentials {
private Credentials credentials = new Credentials();
}
But I can't get my class to load the properties. How can I get it to work in this scenario?
Just make a separate configuration bean and access value from that try below code
#Configuration
#Getter
#Setter
#ConfigurationProperties("credentials")
public class MyCredentialSetting{
private String userid;
private String password;
}
Now wherever you want to use just use #Autowired like in controller or service
Here myCredentialSetting has value from propertoes file injected by spring boot automatically
#Autowired
private MyCredentialSetting myCredentialSetting;
String userIdValue=myCredentialSetting.getUserid(); //you will get user id value by this
String password=myCredentialSetting.getPassword();
//Setting value to original pojo for furthur use
private Credentials credentials = new Credentials();
credentials.setUserid(userIdValue);
credentials.setPassword(password);
You are mixing things.
#Setter (and #Getter) are most likely lombok project annotations.
These annotations at compile time will generate the getX() and setX() methods on a Pojo with a property "x".
If the Credentials POJO is in another jar, it should have a getter and setter (or it is not a POJO). So we don't care about lombok.
On another side you have a #Configuration class where Spring boot will create the different beans of your application.
The class should look something like this:
#Configuration
#ConfigurationProperties("credentials")
public class MyCredentials {
#Bean("credentials")
public Credentials credentials(
#Value("${credentials.userid}") String userid,
#Value("${credentials.password}") String password) {
Credentials credentials = new Credentials();
credentials.setUserid(userid);
credentials.setPassword(password):
return credentials;
}
}
With the #Value annotation Spring boot will inject the properties into the method that will create the bean.
EDIT I
As stated by #M.Deinum, the same can be obtained by:
#Configuration
public class MyCredentials {
#Bean("credentials")
#ConfigurationProperties("credentials")
public Credentials credentials() {
return new Credentials();
}
}
#ConfigurationProperties will find the properties prefixed with "credentials" and inject them into the credentials bean.
Thanks for the tip #M.Deinum!
I have a configuration class like below. All of fields in the inner class OptionalServiceConfigs has a default value as annotated using #Value as shown in below.
Sometimes in my application.properties file, it does not have a single service prefixed property. In that case, we want to have loaded an OptionalServiceConfigs instance with its default field values.
#Configuration
#ConfigurationProperties(prefix = "myconf")
public class MyConfigs {
// ... rest of my configs
#Value("${service:?????}") // what to put here, or can I?
private OptionalServiceConfigs service; // this is null
// In this class all fields have a default value.
public static class OptionalServiceConfigs {
#Value("${mode:local}")
private String mode;
#Value("${timeout:30000}")
private long timeout;
// ... rest of getter and setters
}
// ... rest of getter and setters
}
But unfortunately, the service field is null when it is accessed using its getter method. Because spring boot does not initialize an instance of it when there is no property keys found with prefixed myconf.service.* in my application.properties file.
Question:
How can I make service field to initialize to a new instance along with its specified default field values when there are no corresponding prefixed keys in properties file?
I can't imagine a value to put in annotation #Value("${service:?????}") for service field.
Nothing works, tried, #Value("${service:}") or #Value("${service:new")
Based on #M. Deinum's advice, did some changes to configuration class. I am a newbie to Spring and it seems I have misunderstood how Spring works behind-the-scenes.
First I removed all #Value annotation from inner class (i.e. OptionalServiceConfigs), and as well as service field in MyConfigs class.
Then, initialized all inner class fields with their default values inline.
In the constructor of MyConfigs, I initialized a new instance of OptionalServiceConfigs for the field service.
By doing this, whenever there is no service related keys in my application.properties a new instance has already been created with default values.
When there is/are service related key/s, then Spring does override my default values to the specified values in application.properties only the field(s) I've specified.
I believe from Spring perspective that there is no way it can know in advance that a referencing field (i.e. service field) would be related to the configurations, when none of its keys exist in the configuration file. That must be the reason why Spring does not initialize it. Fair enough.
Complete solution:
#Configuration
#ConfigurationProperties(prefix = "myconf")
public class MyConfigs {
// ... rest of my configs
private OptionalServiceConfigs service;
public static class OptionalServiceConfigs {
private String mode = "local";
private long timeout = 30000L;
// ... rest of getter and setters
}
public MyConfigs() {
service = new OptionalServiceConfigs();
}
// ... rest of getter and setters
}
you can try such a structure which works for me quite fine:
#Data
#Validated
#ConfigurationProperties(prefix = "gateway.auth")
#Configuration
public class AuthProperties {
#NotNull
private URL apiUrl;
#Valid
#NotNull
private Authentication authentication;
#Data
public static class Authentication {
#NotNull
private Duration accessTokenTtl;
#NotNull
private String accessTokenUri;
#NotNull
private String clientId;
#NotNull
private String clientSecret;
#NotNull
private String username;
#NotNull
private String password;
#Min(0)
#NonNull
private Integer retries = 0;
}
}
Important is to have getters and setters in order to enable Spring to postprocess ConfigurationProperties, I am using Lombok (#Data) for this.
please see here for more details:
Baeldung ConfigurationProperties Tutorial
I get userId from request.getRemoteUser(), I want to store it somewhere and get from any layer of application. I don't want to pass the userId from controller to other layers or store it in context. Is there anything similar to this, so that simply autowired userId and use it anywhere.
I'm using Spring-boot and Spring-rest controller.
#Configuration
public class ConfigurationClass {
private #Value("#{ request.getRemoteUser() }") String userId;
#Bean("userId")
#Scope("request")
public String getUserId() {
return userId;
}
I am tring to implement logging of users in Spring Security on the basis of a popular Tutorial and have a doubt about how spring beans are wired.
The below class is defined as a standard bean in the Spring Context
public class ActiveUserStore {
public List<String> users;
public ActiveUserStore() {
users = new ArrayList<String>();
}
public List<String> getUsers() {
return users;
}
public void setUsers(List<String> users) {
this.users = users;
}
}
The above is defined as a Bean through
#Bean
public ActiveUserStore activeUserStore(){
return new ActiveUserStore();
}
And the Bean is being used in the below class, please note the users.add(user.getUsername());
#Component
public class LoggedUser implements HttpSessionBindingListener {
private String username;
private ActiveUserStore activeUserStore;
public LoggedUser(String username, ActiveUserStore activeUserStore) {
this.username = username;
this.activeUserStore = activeUserStore;
}
public LoggedUser() {}
#Override
public void valueBound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (!users.contains(user.getUsername())) {
users.add(user.getUsername());//HOW IS THIS SAVED TO THE ACTIVEUSERSTORE BEAN
}
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (users.contains(user.getUsername())) {
users.remove(user.getUsername());//HOW IS THIS SAVED TO THE ACTIVEUSERSTORE BEAN
}
}
My Question: Since users variable belongs to the ActiveUserStore Bean, how does the following line of code inside the valueBound and valueUnbound methods of Logged User Class, automatically save the ussers data inside the ActiveUserStore Bean ?
users.add(user.getUsername());
I have also marked this line in the code snipped above for clarity.
Any help is appreciated, since I think my understanding of how Beans are wired and used is probably not clear since I am not able to understand the above working. Thanks.
Think about Spring Bean as usual Java class. This class instantiated by Spring at application start just once (actually this is not always true, but by default it is)
Now you inside of your bean, you have reference to List variable and get it with:
List<String> users = activeUserStore.getUsers();
Now users variable contains reference to the List stored in bean. This is because in Java objects are passed by reference.
LoggedUser user = (LoggedUser) event.getValue();
if (!users.contains(user.getUsername())) {
and here users variable contains List class reference. List class have method add, and LoggedUser have getUsername method. As users variable refers to same List object as your bean property contain, this adds username to your bean:
users.add(user.getUsername());
}