I am studying a spring exmaple. And I found the following code. I can't understand the construct function. A validator interface is passed to this function. How is this validator generated? Thanks in advance.
#Controller
#RequestMapping(value="/account")
public class AccountController {
private Map<Long, Account> accounts = new ConcurrentHashMap<Long, Account>();
private Validator validator;
#Autowired
public AccountController(Validator validator) {
this.validator = validator;
}
#RequestMapping(method=RequestMethod.POST)
public #ResponseBody Map<String, ? extends Object> create(#RequestBody Account account, HttpServletResponse response) {
Set<ConstraintViolation<Account>> failures = validator.validate(account);
if (!failures.isEmpty()) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return validationMessages(failures);
} else {
accounts.put(account.assignId(), account);
return Collections.singletonMap("id", account.getId());
}
}
The validator can be any class that implements Springs Validator interface and is available in the current application context. By default Spring autowires by type. This means that every bean which implements the Validator interface can satisfy the constructor of AccountController. I don't know the exact example but there might be something like an AccountValidator bean available int the application context.
Be aware that this approach could cause problem if multiple validator beans are available in the application context.
See the Validation section in the spring documentation for details on the Validator interface.
When You use Autowired on constructor Spring looks for Validator implementation/
In this example Spring injects its default Validator implementation:
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
Here's more:
section: 5.7.2.1 Injecting a Validator
http://docs.spring.io/spring/docs/3.0.0.RC3/reference/html/ch05s07.html
There must be some concrete implementation of Validator.Without that it is not possible.
Further to support my answer see that it is being #Autowired.
Please post the link from which you are studying or check the source code for the presence of validaor class.
Also,check this link There is no concrete implementation by default.
Related
I will try to ignore other details and make it short:
#Entity
public class User
#UniqueEmail
#Column(unique = true)
private String email;
}
#Component
public class UniqueEmailValidatior implements ConstraintValidator<UniqueEmail,String>, InitializingBean {
#Autowired private UserService userService;
#Override
public void initialize(UniqueEmail constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if(userService == null) throw new IllegalStateException();
if(value == null) return false;
return !userService.isEmailExisted(value);
}
}
This will work when the validation is made in Spring (Spring MVC #Valid or inject the Validator using #Autowire), everything will be fine.
But as soon as I save the entity using Spring Data JPA:
User save = userRepository.save(newUser);
Hibernate will try to instantiate a new UniqueEmailValidatior without inject the UserService bean.
So how can I make Hibernate to use my UniqueEmailValidatior component without it instantiate a new one.
I could disable hibernate validation using spring.jpa.properties.javax.persistence.validation.mode=none but I hope there is another way
Update: Here is my UserService:
#Autowired private Validator validator;
#Transactional
public SimpleUserDTO newUser(UserRegisterDTO user) {
validator.validate(user);
System.out.println("This passes");
User newUser = new User(user.getUsername(),
passwordEncoder.encode(user.getPassword()),user.getEmail(),
"USER",
user.getAvatar());
User save = userRepository.save(newUser);
System.out.println("This won't pass");
return ....
}
I would expect that Spring Boot would wire the existing validator to the EntityManager apparently it doesn't.
You can use a HibernatePropertiesCustomizer and add properties to the existing EntityManagerFactoryBuilder and register the Validator.
NOTE: I'm assuming here that you are using Spring Boot 2.0
#Component
public class ValidatorAddingCustomizer implements HibernatePropertiesCustomizer {
private final ObjectProvider<javax.validation.Validator> provider;
public ValidatorAddingCustomizer(ObjectProvider<javax.validation.Validator> provider) {
this.provider=provider;
}
public void customize(Map<String, Object> hibernateProperties) {
Validator validator = provider.getIfUnique();
if (validator != null) {
hibernateProperties.put("javax.persistence.validation.factory", validator);
}
}
}
Something like this should wire the existing validator with hibernate and with that it will make use of auto wiring.
NOTE: You don't need to use #Component on the validator the autowiring is build into the validator factory before returning the instance of the Validator.
To have the Spring beans injected into your ConstraintValidator, you need a specific ConstraintValidatorFactory which should be passed at the initialization of the ValidatorFactory.
Something along the lines of:
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.constraintValidatorFactory( new MySpringAwareConstraintValidatorFactory( mySpringContext ) )
.build();
with MySpringAwareConstraintValidatorFactory being a ConstraintValidatorFactory that injects the beans inside your ConstraintValidator.
I suspect the ValidatorFactory used by Spring Data does not inject the validators when creating them, which is unfortunate.
I suppose you should be able to override it. Or better, you should open an issue against Spring Boot/Spring Data so that they properly inject the ConstraintValidators as it the second time in a row we have this question on SO.
The answer is quite big to post here. Please check for this article in S.O to help you with. This should help you get started.
Test Custom Validator with Autowired spring Service
The problem is hibernate will no way know spring definition. However you can make Entities to be aware of any type of javax.validation types. Hope this helps.
I can't find a simple way to inject a component/service given a runtime value.
I started reading # Spring's doc: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers
but I can't find there how to variabilize the values passed to the #Qualifier annotation.
Let's say I've got a model entity with such interface:
public interface Case {
String getCountryCode();
void setCountryCode(String countryCode);
}
In my client code, I would do something like:
#Inject
DoService does;
(...)
Case myCase = new CaseImpl(); // ...or whatever
myCase.setCountryCode("uk");
does.whateverWith(myCase);
... with my service being:
#Service
public class DoService {
#Inject
// FIXME what kind of #$#& symbol can I use here?
// Seems like SpEL is sadly invalid here :(
#Qualifier("${caze.countryCode}")
private CaseService caseService;
public void whateverWith(Case caze) {
caseService.modify(caze);
}
}
I expect the caseService to be the UKCaseService (see related code below).
public interface CaseService {
void modify(Case caze);
}
#Service
#Qualifier("uk")
public class UKCaseService implements CaseService {
}
#Service
#Qualifier("us")
public class USCaseService implements CaseService {
}
So how do I "fix" all of this in the most simple / elegant / efficient way by using either/all Spring feature(s), so essentially NO .properties, NO XML, only annotations.
However I already suspect something is wrong in my DoService because Spring would need to know the "case" before injecting the caseService... but how to achieve this without the client code knowing about the caseService?!
I can't figure this out...
I already read several issues here on SO, but most of the times either they don't really have the same needs and/or config as I have, or the posted answers aren't enough satisfying to me (look like they're essentially workarounds or (old) usage of (old) Spring features).
How does Spring autowire by name when more than one matching bean is found?
=> only refers to component-like classes
Dynamically defining which bean to autowire in Spring (using qualifiers)
=> really interesting but the most elaborated answer (4 votes) is... almost 3 1/2 years-old?! (July 2013)
Spring 3 - Dynamic Autowiring at runtime based on another object attribute
=> quite similar problem here, but the answer really look like a workaround rather a real design pattern (like factory)? and I don't like implementing all the code into the ServiceImpl as it's done...
Spring #Autowiring, how to use an object factory to choose implementation?
=> 2nd answer seems interestingly but its author does not expand, so altough I know (a bit) about Java Config & stuff, I'm not really sure what he's talking about...
How to inject different services at runtime based on a property with Spring without XML
=> interesting discussion, esp. the answer, but the user has properties set, which I don't have.
Also read this:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-bean-references
=> I can't find expanded examples about the use of "#" in expressions. Does someone know about this?
Edit:
Found other related-to-similar issues, no one got a proper answer:
How to use #Autowired to dynamically inject implementation like a factory pattern
Spring Qualifier and property placeholder
Spring: Using #Qualifier with Property Placeholder
How to do conditional auto-wiring in Spring?
Dynamic injection in Spring
SpEL in #Qualifier refer to same bean
How to use SpEL to inject result of method call in Spring?
Factory Pattern might be a solution?
How to use #Autowired to dynamically inject implementation like a factory pattern
You can obtain your bean from the context by name dynamically using a BeanFactory:
#Service
public class Doer {
#Autowired BeanFactory beans;
public void doSomething(Case case){
CaseService service = beans.getBean(case.getCountryCode(), CaseService.class)
service.doSomething(case);
}
}
A side note. Using something like country code as bean name looks a bit odd. Add at least some prefix or better consider some other design pattern.
If you still like to have bean per country, I would suggest another approach. Introduce a registry service to get a required service by country code:
#Service
public class CaseServices {
private final Map<String, CaseService> servicesByCountryCode = new HashMap<>();
#Autowired
public CaseServices(List<CaseService> services){
for (CaseService service: services){
register(service.getCountryCode(), service);
}
}
public void register(String countryCode, CaseService service) {
this.servicesByCountryCode.put(countryCode, service);
}
public CaseService getCaseService(String countryCode){
return this.servicesByCountryCode.get(countryCode);
}
}
Example usage:
#Service
public class DoService {
#Autowired CaseServices caseServices;
public void doSomethingWith(Case case){
CaseService service = caseServices.getCaseService(case.getCountryCode());
service.modify(case);
}
}
In this case you have to add String getCountryCode() method to your CaseService interface.
public interface CaseService {
void modify(Case case);
String getCountryCode();
}
Alternatively, you can add method CaseService.supports(Case case) to select the service. Or, if you cannot extend the interface, you can call CaseServices.register(String, CaseService) method from some initialiser or a #Configuration class.
UPDATE: Forgot to mention, that Spring already provides a nice Plugin abstraction to reuse boilerplate code for creating PluginRegistry like this.
Example:
public interface CaseService extends Plugin<String>{
void doSomething(Case case);
}
#Service
#Priority(0)
public class SwissCaseService implements CaseService {
void doSomething(Case case){
// Do something with the Swiss case
}
boolean supports(String countryCode){
return countryCode.equals("CH");
}
}
#Service
#Priority(Ordered.LOWEST_PRECEDENCE)
public class DefaultCaseService implements CaseService {
void doSomething(Case case){
// Do something with the case by-default
}
boolean supports(String countryCode){
return true;
}
}
#Service
public class CaseServices {
private final PluginRegistry<CaseService<?>, String> registry;
#Autowired
public Cases(List<CaseService> services){
this.registry = OrderAwarePluginRegistry.create(services);
}
public CaseService getCaseService(String countryCode){
return registry.getPluginFor(countryCode);
}
}
According to this SO answer, using #Qualifier isn't going to help you much: Get bean from ApplicationContext by qualifier
As for an alternative strategy:
if you are spring boot, you could use #ConditonalOnProperty or another Conditional.
a lookup service, as #aux suggests
just name your beans consistently and look them up by name at runtime.
Note that your use case also appears to revolve around the scenario where beans are created on application startup, but the bean chosen needs to be resolved after the applicationContext has finished injecting the beans.
I am using spring hateoas in spring and got the problem is spring could not instance hateoas resource assembler , here is my snippet code:
UserHateoasResourceAssembler.java:
#Service
public class UserHateoasResourceAssembler extends ResourceAssemblerSupport<UserDTO, UserHateoasResource> {
public UserHateoasResourceAssembler() {
super(UserController.class, UserHateoasResource.class);
}
#Override
public UserHateoasResource toResource(UserDTO entity) {
UserHateoasResource resource = createResourceWithId(entity.getId(), entity);
return resource;
}
#Override
protected UserHateoasResource instantiateResource(UserDTO entity) {
return new UserHateoasResource(entity);
}
}
UserController.java:
#RestController
#RequestMapping("/api/")
public class UserController {
#Inject
private UserHateoasResourceAssembler userAssembler ;
....
}
The exception was thrown is "No qualifying bean of type [UserHateoasResourceAssembler] found for dependency. I know this root cause is can not create instance of assembler.
I tried to use #Service or #Component but both does not work. I also tried to use #Autowire instead, but did not work too. I have to fix that by adding #Scope( proxyMode = ScopedProxyMode.TARGET_CLASS). But I wonder if there is any another solution to resolve it instead of using #Scope ?
Thanks.
I found the elegant solution. Due to my application using generated code and it used #EnableAspectJAutoProxy, this annotation default set auto-proxy = false and using JDK proxy, so almost the instance of class that implementing an interface was not allowed. We have to #inject the interface instead. So to inject the implementation class, have 2 options here:
Set #EnableAspectJAutoProxy(proxyTargetClass = true )
Remove this annotation if we does not really need that.
I'm trying to build a small POC to check if we can use Spring Validation on our projects (REST Endpoints). The goal is to use the #Valid annotation on some Component's methods, annotate arguments with JSR-303 annotations and build some Validator instances for custom validation logic.
Consider the following scenario:
Account (Getters and Setters ommited)
public class Account {
private int id;
#Min(0) private double amount;
#NonNull private String cardholder;
}
AccountController
#RestController
#RequestMapping("/account")
public class AccountController {
#Autowired private AccountService service;
#RequestMapping(method= RequestMethod.POST)
public void post(#RequestBody Account account) {
service.save(account);
}
}
AccountService
#Component
public class AccountService {
public void save(**#Valid** Account account) {
// Logic ommited
log.info("Account saved!");
}
}
AccountSaveValidator
public class AccountSaveValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) { return Account.class.isAssignableFrom(clazz); }
#Override
public void validate(Object target, Errors errors) {
Account account = (Account) target;
if (**if account does not exist**)
errors.rejectValue("id", "account.not-exists");
}
}
Whenever I POST to /account, the mentioned validations do not run, and the Account saved! message is displayed regardless. However, if I put the #Valid annotation on the AccountController's POST handler instead, the validations are executed.
I was only able to execute only the custom validation (AccountSaveValidator) manually by calling it on the save() method like this:
ValidationUtils.invokeValidator(new AccountSaveValidator(), account, errors);
if (errors.hasErrors()) {
throw new ValidationException(errors);
}
What am I missing here? I've read that these validation components are normally used along with Spring-MVC, but that it could be used without it.
The gradle dependencies I have are the following:
compile "org.springframework:spring-core"
compile "org.springframework:spring-context"
compile "org.springframework:spring-web"
compile "org.springframework.boot:spring-boot"
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-autoconfigure"
compile "javax.validation:validation-api:1.1.0.Final"
compile "org.hibernate:hibernate-validator:5.2.4.Final"
A couple things, I believe that your title on the question here is a bit misrepresentitive of what you are actually asking here. You are not trying to validate a spring Component. You wish to do method parameter validation within a Spring Component, which is different. I believe that your question here is a duplicate of this question: JSR 303. Validate method parameter and throw exception. There are examples there of how to do what you want to do using proxies and a MethodValidationInterceptor.
I will add some additional information here to try to clarify the differences in where JSR-303 validation works and why.
Spring MVC Parameters: Parameters passed into Spring MVC Components are resolved using a combination of user defined and default HandlerParameterResolvers. Part of Spring's default MVC configuration includes hooks for automatic mappings via #RequestParam and #PathVariable to raw types and #RequestBody to Objects all via the afore mentioned HandlerParameterResolver. In the same way that these HandlerParameterResolvers are automatically configured in Spring (mostly by default) there are also Validators that are registered to the DataBinders, which map the data from the request to the params above, JSR-303 validation is automatically configured to tie into these hooks. This of course is a simplified summary of what is going on behind the scenes.
Spring Components/Beans: Spring Beans and Components are validated by a Spring Bean Validator. You can find details on this here: http://docs.spring.io/autorepo/docs/spring/3.2.x/spring-framework-reference/html/validation.html as described in the section called "7.8.2 Configuring a Bean Validation Implementation"
I have the following problem.
I have a generic class A
public class A<T, DAO extends JpaRepository<?, ?>>
{
#Autowired
protected DAO daoObject;
......
and there I am trying inject a genreic DAO-object of the JpaRepository-type.
If I have only one implemetation of injected object(of JpaRepository), then there is no problem, but if I have more then one, then spring doesn't know which object it is to inject and throws an exception.
The question is: How can I dynamish based on generic information, inject the correct object?
Thank you.
public interface IRegisteredUserDAO extends JpaRepository<RegisteredUser, String> {
}
public interface IMailLogDao extends JpaRepository<MailLog, Long> {
findByTo(String to);
}
and i used it so
public class RegisteredUserVM extends YBTableViewModel<RegisteredUser, IRegisteredUserDAO>
{
UPDATE:
public class MailLogVM extends YBTableViewModel<MailLog, IMailLogDao>
{
}
You should be able to do this using the latest Spring 4 RC1. Versions before that do not support generic injection at all. See this ticket and related commits for details.
You can use Spring's #Qualifier annotation to inject the correct bean:
#Autowired
#Qualifier("IRegisteredUserDAOImpl")
protected DAO daoObject;
Here the bean with qualifier value "IRegisteredUserDAOImpl" is wired.