javax validation api not working for pojo validation - spring

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.

Related

Why SpringBoot validation not work with single #PropertySource

My Source code:
Person.java
#Component
#Validated
#PropertySource(value = "classpath:person.yaml")
#Data
public class Person {
#NotNull(message = "test can't be null")
private String test;
#Value("${name}")
private String name;
#Autowired
private Cat pet;
#Max(value=120,message="invalid age")
#Value("${age}")
private int age;
#Email(message = "invalid email address")
#Value("${email}")
private String email;
}
person.yaml
name: "test"
email: "abcdefg"
age: 11111
I use my Person class on SpringBootApplication with invalid email address and age, but it ran successfully without any validation exception.
But If I replace the #PropertySource(value = "classpath:person.yaml") to #ConfigurationProperties(prefix = "person") or use both #PropertySource and #ConfigurationProperties
application.yaml
person:
name: "test"
email: "abcdefg"
age: 11111
My SpringBoot throw an validation exception successfully.
From #PropertySource documantation:
Annotation providing a convenient and declarative mechanism for adding a PropertySource to Spring's Environment. To be used in conjunction with #Configuration classes.
You don't have #Configuration anotation under class declaration.
Your second example has #ConfigurationProperties annotation and this is from documentation:
Annotation for externalized configuration. Add this to a class definition or a #Bean method in a #Configuration class if you want to bind and validate some external Properties (e.g. from a .properties file).
In a nutshell: #PropertySource need #Configuration but #ConfigurationProperties not.

Spring Boot #ConfigurationProperties, skip #Configuration if not valid

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.

#AllArgsConstructor and Constructor Injection with Spring: is private final needed?

Let's say I have the following constructor injection (not Autowiring):
#Service
public class FooService {
private final OrderService orderService;
public FooService(OrderService orderService) {
this.orderService = orderService;
}
}
That can be replaced with:
#Service
#AllArgsConstructor
public class FooService {
private final OrderService orderService;
}
Do I need to declare this as private and final to inject this service? Does Lombok take care of this like they do with #Data and beans? Any side-effects?
You should use #RequiredArgsConstructor instead, you need a single primary constructor to fill the required fields. So you marked them final and use this annotation to generate a primary constructor.
#AllArgsConstructor is bug-prone, because it may produce multiple constructors which Spring may fail to handle.
In your particular case the results of #AllArgsConstructor and #RequiredArgsConstructor just happen to be the same, because you have just one final field.
Note that, Spring documentation encourages the usage of constructor-based injection (https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection), and recommends to avoid using several injection techniques together.
#Service
#RequiredArgsConstructor
public class FooService {
private final OrderService orderService;
}
According to documentation
#AllArgsConstructor generates a constructor with 1 parameter for each field in your class. Fields marked with #NonNull result in null checks on those parameters.
So, no, it does not make your fields private & final as for example #Value annotation.

#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

Resources