Spring Boot #ConfigurationProperties, skip #Configuration if not valid - spring-boot

In a Spring Boot 1.5.13 project, I have a #Configuration object with some #NotEmpty fields:
#Configuration
#Validated
public class Test {
#NotEmpty
private String name;
private String optionalOne;
private String optionalTwo;
#NotEmpty
private String location;
...
}
And a #ConfigurationProperties class that loads it from application.yml:
#ConfigurationProperties(prefix="test.config")
public class TestConfig {
#Valid
Map<String, Test> testRecords = new HashMap<>();
...
}
There are several "Test" records in the configuration files.
Default behavior from spring is that if validation fails, like if one of the records has a missing location, then an error prevents the app from starting up.
I would instead like the behavior to be that the invalid record is logged and skipped, so that the app continues startup, loading only the valid records, and loading no records that are missing the #NotEmpty fields.
How can I accomplish this?

I would suggest you to implement the validation yourself without any annotations. After the beans are constructed check the constraints programatically (maybe in a #PostConstruct method) to avoid fighting with Spring.

Related

javax validation api not working for pojo validation

I have a POJO class where the class variables are getting injected by #Value annotation. I am trying to validate my class variables using javax validation api & so I have tried #NotNull, #NotEmpty and #NotBlank, but all of them seem not to be validating or throwing any kind of exception even when a blank/null value is present in the application.yml file. Any idea as to how can I validate my POJO here using the javax validation api?
PS: I am using lombok to generate my getter/setter.
Below is my sample code!
POJO Class:
#Component
#Getter
#Setter
public class Credentials {
#NotBlank
#Value("${app.username}")
private String user_name;
#NotBlank
#Value("${app.password}")
private String password;
}
Below is the application.yml file:
app:
username: '#{null}'
password: passWord
Even if I provide a blank value, I don't get any exception when I try to print these values in the console.
I think this can be applied.
#Data
#RequiredArgsConstructor
public class Credentials {
private final String user_name;
private final String password;
}
#Configuration
#Validated
public class CredentialsConfiguration {
#Bean
public Credentials credentials(
#NotBlank #Value("${app.username}") final String user_name,
#NotBlank #Value("${app.password}") final String password) {
return new Credentials(user_name, password);
}
}
Validation will only work for #ConfigurationProperties annotated classes combined with using #EnableConfigurationProperties.
The reason you don't get any exception is that #Value only looks for presence of the attribute in the properties, it doesn't care what the value of that attribute is, unless you are assigning a mis-matching datatype value.

spring boot 2: load application.properties manually

is it possible to access application.properties values while creating datasource in SpringApplication.run?
I have tried to inject value with #Value but when i need the values, the bean with #ConfigurationProperties is not created yet.
if you are referring to data source url,username and password you can use these keys :
spring.datasource.url=your_database_url_and_port_number
spring.datasource.username=your_database_username
spring.datasource.password=your_username_passsword
You need to add #EnableConfigurationProperties annotation mentioning the properties POJO name.
#SpringBootApplication
#EnableConfigurationProperties(ConfigProperties.class)
Then in the ConfigProperties class you need to add the below annotation.Prefix is what you will set in the properties file.
#ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
private String hostName;
private int port;
private String from;
// standard getters and setters
}
Values in properties file.
#Simple properties
mail.hostname=host#mail.com
mail.port=9000
mail.from=mailer#mail.com

#CreatedBy becomes null when updating

I have this entity:
#Entity
#EntityListeners( AuditingEntityListener.class )
public class Employee {
#Id
#GeneratedValue
int id;
private String name;
...
#LastModifiedBy
private String modifiedBy;
#CreatedBy
private String createdBy;
}
And i have this config class:
#Configuration
#EnableJpaAuditing
public class DataConfig {
#Bean
public AuditorAware<String> auditorAware() {
return () ->
SecurityContextHolder.getContext().getAuthentication().getName();
}
}
The problem is:
When updating entity, the created_by becomes null.
Any help please.
I'd suggest to you to ensure if your spring boot app is scanning the DataConfig class.
In addition, well in case of having a REST Service (I don't know because that info is not added to the question) but bear in mind a REST Service is Stateless, and you need fetch the Authorization from the request to add it to the spring security context BEFORE executing the request.
But if your spring boot app is just a Spring MVC one with basic Authorization, be sure you have an open session once the data is updated/created

Spring Boot Use Custom Properties Service

I am working on a legacy project that has its own PropertyService class that manages the reloadable properties and so on.
The thing works pretty much OK, but the problem is now I have this property service, for my project, and an application.yml for the spring boot related properties.
The question is: is there a way to tell spring boot to load properties from something like a properties provider - a custom class or an adapter of sort ?
In this way I could manage my properties only through the existing module
Thank you for your help !
Try #ConfigurationProperties to customize the properties loading (see the example)
The code example
#Configuration
#ConfigurationProperties(locations = "classpath:mail.properties", prefix = "mail")
public class MailConfiguration {
public static class Smtp {
private boolean auth;
private boolean starttlsEnable;
// ... getters and setters
}
#NotBlank
private String host;
private int port;
private String from;
private String username;
private String password;
#NotNull
private Smtp smtp;
// ... getters and setters
#Bean
public JavaMailSender javaMailSender() {
// omitted for readability
}
}
So you define a bean which in fact returns properties

#Autowired in Spring MVC #Controller does not work on a private field

I have a Spring MVC Controller in a very XML-slimmed application, we use a lot of annotations and as little config as possible. The Controller is working and it also has a number of resource values injected. But I've experienced a really strange behavior with this controller; annotated private fields referencing other components will not be injected.
This will not work.
#Controller
public class EntranceUnitController {
#Value("${remote.baseUrl}")
private String baseUrl = "http://localhost";
#Value("${remote.port}")
private String pushPort = "8080";
#Autowired
private HttpClientFactory httpClientFactory;
...
It seems that the httpClientFactory isn't there yet when the private fields are set, if I set a break point to inspect the value there is of course null set when the controller is created.
BUT, if I make a setter for the component and annotate the set-method instead of the private field the controller works as expected.
#Controller
public class EntranceUnitController {
#Value("${remote.baseUrl}")
private String baseUrl = "http://localhost";
#Value("${remote.port}")
private String pushPort = "8080";
private HttpClientFactory httpClientFactory;
#Autowired
public void setHttpClientFactory(HttpClientFactory httpClientFactory) {
this.httpClientFactory = httpClientFactory;
}
...
To me this is really annoying. Isn't the auto wiring injection for annotated values happening at the same time regardless injection point? I.e. why does it matter that the object is injected with a setter? I thought that private field injections are directly followed by constructs and setters, me start to think I'm wrong in that case...
Seems like your dependencies are in fact injected, you are just putting a breakpoint in the wrong moment (too early) and the dependencies aren't injected yet, despite class being already created.
Remember that, unless you are using constructor injection, the first place where you can use injected dependencies is #PostConstruct method:
#Controller
public class EntranceUnitController {
#Autowired
private HttpClientFactory httpClientFactory;
#PostConstruct
public void init() {
httpClientFactory //should not be null
}

Resources